home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / util / gnu / gnu_oleo_1_2_2.lha / oleo-1.2.2 / ref.c < prev    next >
C/C++ Source or Header  |  1993-03-03  |  68KB  |  2,868 lines

  1. /*    Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.
  2.  
  3. This file is part of Oleo, the GNU Spreadsheet.
  4.  
  5. Oleo is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.
  9.  
  10. Oleo is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with Oleo; see the file COPYING.  If not, write to
  17. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. #include "funcdef.h"
  20. #include <stdio.h>
  21. #include <ctype.h>
  22. #include <sys/types.h>
  23. #include <signal.h>
  24. #include "sysdef.h"
  25. #include "global.h"
  26. #include "cell.h"
  27. #include "eval.h"
  28. #include "io-abstract.h"
  29. #include "io-generic.h"
  30. #include "hash.h"
  31. #include "byte-compile.h"
  32. #include "parse.h"
  33. #include "ref.h"
  34.  
  35.  
  36. #ifdef __STDC__
  37. static void add_ref_fm (struct ref_fm **, CELLREF, CELLREF);
  38. static void flush_ref_fm (struct ref_fm **, CELLREF, CELLREF);
  39. static void flush_range_ref (struct rng *, CELLREF, CELLREF);
  40. extern void shift_formula (int r, int c, int dn, int ov);
  41. #ifdef SPLIT_REFS
  42. /* These two are tunable paramaters */
  43. #define REF_START    3
  44. #define REF_INC        *=2
  45. #else
  46. static void flush_ref_to (struct ref_to **);
  47. static void flush_fm_ref (struct ref_fm *);
  48. #endif /* SPLIT_REFS */
  49.  
  50. #else /* !__STDC__ */
  51.  
  52. static void add_ref_fm ();
  53. static void flush_ref_fm ();
  54. static void flush_range_ref ();
  55. extern void shift_formula ();
  56.  
  57. #ifdef SPLIT_REFS
  58. /* These two are tunable paramaters */
  59. #define REF_START    3
  60. #define REF_INC        *=2
  61. #else
  62. static void flush_ref_to ();
  63. static void flush_fm_ref ();
  64. #endif /* SPLIT_REFS */
  65. #endif /* __STDC__ */
  66.  
  67. /* More tunable paramaters */
  68.  
  69. #define FIFO_START    40
  70. #define FIFO_INC    *=2
  71.  
  72. #define TO_MAGIC(row,col)    (((long)(row)<<BITS_PER_CELLREF)|(col))
  73. #define MAGIC_ROW(magic)    (((magic)>>BITS_PER_CELLREF)&CELLREF_MASK)
  74. #define MAGIC_COL(magic)    ((magic)&CELLREF_MASK)
  75.  
  76. #define BETWEEN(mid,lo,hi)    ((mid>=lo)&&(mid<=hi))
  77.  
  78. static VOIDSTAR moving;
  79.  
  80. /* These three for async cell updating */
  81. extern unsigned signal_ticks;
  82.  
  83. int timer_active = 0;
  84. struct ref_fm *timer_cells;
  85.  
  86. CELL *my_cell;
  87.  
  88. #ifdef TEST
  89. extern int debug;
  90. #endif
  91.  
  92. /* Functions for dealing exclusively with variables */
  93. struct hash_control *the_vars;
  94.  
  95. struct value
  96.   {
  97.     int type;
  98.     union vals c_z;
  99.   };
  100.  
  101. /* For the fifo-buffer */
  102. struct pos
  103.   {
  104.     CELLREF row;
  105.     CELLREF col;
  106.   };
  107.  
  108. struct cell_buf
  109.   {
  110.     unsigned int size;
  111.     struct pos *buf;
  112.     struct pos *push_to_here;
  113.     struct pos *pop_frm_here;
  114.   };
  115.  
  116.  
  117. /* Set the cell ROW,COL to STRING, parsing string as needed */
  118. void
  119. set_cell (row, col, string)
  120.      CELLREF row;
  121.      CELLREF col;
  122.      char *string;
  123. {
  124.   unsigned char *ret;
  125.  
  126.   cur_row = row;
  127.   cur_col = col;
  128.  
  129. #ifdef TEST
  130.   if (!string)
  131.     {
  132.       io_error_msg ("Null string to set_cell %s", cell_name (row, col));
  133.       return;
  134.     }
  135. #endif
  136.   while (*string == ' ')
  137.     string++;
  138.  
  139.   if (!*string)
  140.     {
  141.       my_cell = find_cell (cur_row, cur_col);
  142.       if (!my_cell)
  143.     return;
  144.       flush_old_value ();
  145.       return;
  146.     }
  147.  
  148.   my_cell = find_or_make_cell (cur_row, cur_col);
  149.   flush_old_value ();
  150.  
  151.   ret = parse_and_compile (string);
  152.   my_cell->cell_formula = ret;
  153. }
  154.  
  155. extern int default_lock;
  156.  
  157. /* new_value() calls set_cell, but refuses to change locked cells, and
  158.    updates and prints the results.  It returns an error msg on error. . .
  159.  */
  160. #if __STDC__
  161. char *
  162. new_value (CELLREF row, CELLREF col, char *string)
  163. #else
  164. char *
  165. new_value (row, col, string)
  166.      CELLREF row;
  167.      CELLREF col;
  168.      char *string;
  169. #endif
  170. {
  171.   CELL *cp;
  172.  
  173.   cp = find_cell (row, col);
  174.   if (((!cp || GET_LCK (cp) == LCK_DEF) && default_lock == LCK_LCK) || (cp && GET_LCK (cp) == LCK_LCK))
  175.     {
  176.       return "cell is locked";
  177.     }
  178.  
  179.   set_cell (row, col, string);
  180.   if (my_cell)
  181.     {
  182.       update_cell (my_cell);
  183.       if (is_constant (my_cell->cell_formula))
  184.     {
  185.       byte_free (my_cell->cell_formula);
  186.       my_cell->cell_formula = 0;
  187.     }
  188.       io_pr_cell (row, col, my_cell);
  189.       my_cell = 0;
  190.     }
  191.   return 0;
  192. }
  193.  
  194. /* This sets the cell to a constant, stored in VALUE, whose type is in TYPE */
  195. #if __STDC__
  196. char *
  197. set_new_value (CELLREF row, CELLREF col, int type, union vals *value)
  198. #else
  199. char *
  200. set_new_value (row, col, type, value)
  201.      CELLREF row;
  202.      CELLREF col;
  203.      int type;
  204.      union vals *value;
  205. #endif
  206. {
  207.   CELL *cp;
  208.   extern int default_lock;
  209.  
  210.   if (type == TYP_ERR)
  211.     type = 0;
  212.   cur_row = row;
  213.   cur_col = col;
  214.   if (type == 0)
  215.     {
  216.       cp = find_cell (row, col);
  217.       if (cp && GET_TYP (cp))
  218.     {
  219.       if ((GET_LCK (cp) == LCK_DEF && default_lock == LCK_LCK) || GET_LCK (cp) == LCK_LCK)
  220.         return "cell is locked";
  221.       my_cell = cp;
  222.       flush_old_value ();
  223.       SET_TYP (cp, 0);
  224.     }
  225.       my_cell = 0;
  226.       return 0;
  227.     }
  228.   else
  229.     {
  230.       cp = find_or_make_cell (row, col);
  231.       if ((GET_LCK (cp) == LCK_DEF && default_lock == LCK_LCK) || GET_LCK (cp) == LCK_LCK)
  232.     return "cell is locked";
  233.       my_cell = cp;
  234.       flush_old_value ();
  235.       SET_TYP (cp, type);
  236.       /* cp->c_z= *value; */
  237.       switch (type)
  238.     {
  239.     case TYP_FLT:
  240.       cp->cell_flt = value->c_d;
  241.       cp->cell_formula = 0;
  242.       break;
  243.  
  244.     case TYP_INT:
  245.       cp->cell_int = value->c_l;
  246.       cp->cell_formula = 0;
  247.       break;
  248.  
  249.     case TYP_STR:
  250.       cp->cell_str = strdup (value->c_s);
  251.       cp->cell_formula = 0;
  252.       break;
  253.  
  254.     case TYP_BOL:
  255.       cp->cell_bol = value->c_i;
  256.       cp->cell_formula = 0;
  257.       break;
  258.  
  259.     case TYP_ERR:
  260.       cp->cell_err = value->c_i;
  261.       cp->cell_formula = 0;
  262.       break;
  263. #ifdef TEST
  264.     default:
  265.       panic ("Unknown type %d in set_new_value", GET_TYP (cp));
  266. #endif
  267.     }
  268.     }
  269.   push_refs (cp->cell_refs_from);
  270.   io_pr_cell (row, col, cp);
  271.   my_cell = 0;
  272.   return 0;
  273. }
  274.  
  275. /* We're reading in a cell, whose formula is FORM, and whose current value
  276.    is VAL.  Parse both of them. . .  (Parsing of VAL is quite primitive)
  277.  */
  278. #if __STDC__
  279. char *
  280. read_new_value (CELLREF row, CELLREF col, char *form, char *val)
  281. #else
  282. char *
  283. read_new_value (row, col, form, val)
  284.      CELLREF row;
  285.      CELLREF col;
  286.      char *form;
  287.      char *val;
  288. #endif
  289. {
  290.   unsigned char *new_bytes;
  291.   extern double __plinf, __neinf, __nan;
  292.  
  293.   cur_row = row;
  294.   cur_col = col;
  295.   my_cell = find_or_make_cell (cur_row, cur_col);
  296.   flush_old_value ();
  297.   SET_TYP (my_cell, 0);
  298.  
  299.   if (form)
  300.     {
  301.       new_bytes = parse_and_compile (form);
  302.       my_cell->cell_formula = new_bytes;
  303.     }
  304.  
  305.   if (val)
  306.     {
  307.       if (val[0] == '"')
  308.     {
  309.       char *sp, *nsp;
  310.  
  311.       sp = val + 1;
  312.       SET_TYP (my_cell, TYP_STR);
  313.       while (*sp)
  314.         sp++;
  315.       if (*--sp != '"')
  316.         {
  317.           if (*sp == '\r' && sp[-1] == '"')
  318.         --sp;
  319.           else
  320.         panic ("Can't find \" in read_new value");
  321.         }
  322.       *sp = '\0';
  323.       nsp = my_cell->cell_str = ck_malloc (sp - val);
  324.       for (sp = val + 1; *sp;)
  325.         *nsp++ = *sp++;
  326.       *nsp++ = '\0';
  327.     }
  328.       else if (isdigit (val[0]) || val[0] == '.' || val[0] == '-' || val[0] == '+')
  329.     {
  330.       char *v;
  331.  
  332.       v = val;
  333.       SET_TYP (my_cell, TYP_INT);
  334.       my_cell->cell_int = astol (&v);
  335.       if (*v)
  336.         {
  337.           SET_TYP (my_cell, TYP_FLT);
  338.           v = val;
  339.           my_cell->cell_flt = astof (&v);
  340.           if (*v)
  341.         return "unknown number";
  342.         }
  343.     }
  344.       else if (val[0] == '#')
  345.     {
  346.       char **en;
  347.  
  348.       if (!stricmp (tname, val))
  349.         {
  350.           SET_TYP (my_cell, TYP_BOL);
  351.           my_cell->cell_bol = 1;
  352.         }
  353.       else if (!stricmp (fname, val))
  354.         {
  355.           SET_TYP (my_cell, TYP_BOL);
  356.           my_cell->cell_bol = 0;
  357.         }
  358.       else if (!stricmp (iname, val))
  359.         {
  360.           SET_TYP (my_cell, TYP_FLT);
  361.           my_cell->cell_flt = __plinf;
  362.         }
  363.       else if (!stricmp (iname, val))
  364.         {
  365.           SET_TYP (my_cell, TYP_FLT);
  366.           my_cell->cell_flt = __plinf;
  367.         }
  368.       else if (!stricmp (mname, val))
  369.         {
  370.           SET_TYP (my_cell, TYP_FLT);
  371.           my_cell->cell_flt = __neinf;
  372.         }
  373.       else if (!stricmp (nname, val))
  374.         {
  375.           SET_TYP (my_cell, TYP_FLT);
  376.           my_cell->cell_flt = __nan;
  377.         }
  378.       else
  379.         {
  380.           SET_TYP (my_cell, TYP_ERR);
  381.           for (en = ename; *en; en++)
  382.         if (!stricmp (*en, val))
  383.           break;
  384.           if (*en)
  385.         my_cell->cell_err = en - &ename[0];
  386.           else
  387.         my_cell->cell_err = 1;
  388.         }
  389.     }
  390.       else
  391.     panic ("What is a '%s'?", val);
  392.     }
  393.  
  394.   my_cell = 0;
  395.   return 0;
  396. }
  397.  
  398. /* This moves the contents, format, etc from RF,CF to RT,CT  RF or RT may be
  399.    NON_ROW, in which case the cell's contents are moved to/from a static
  400.    storage area.  Moving anything from NON_ROW before moving anything into it
  401.    or moving two things at a time into NON_ROW are both bad ideas. . .
  402.  
  403.    Also note that move_cell does not call move_outside, which may or may not
  404.    be a bug. . .  Move_cell is only called as part of sorting, which is why
  405.    we may *not* want to call move_outside. . .
  406.  */
  407.  
  408. #if __STDC__
  409. void
  410. move_cell (CELLREF rf, CELLREF cf, CELLREF rt, CELLREF ct)
  411. #else
  412. void
  413. move_cell (rf, cf, rt, ct)
  414.      CELLREF rf;
  415.      CELLREF cf;
  416.      CELLREF rt;
  417.      CELLREF ct;
  418. #endif
  419. {
  420.   CELL *cpf;
  421.  
  422.   static CELLREF non_rf, non_cf;
  423.   static struct cell non_cell;
  424.  
  425.   if (rf == NON_ROW)
  426.     {
  427.       cur_row = rt;
  428.       cur_col = ct;
  429.       my_cell = find_cell (cur_row, cur_col);
  430.       if (my_cell)
  431.     flush_old_value ();
  432.       else if (!non_cell.cell_flags && !non_cell.cell_formula
  433.            && !non_cell.cell_font)
  434.     return;
  435.       else
  436.     my_cell = find_or_make_cell (cur_row, cur_col);
  437.  
  438.       my_cell->cell_flags = non_cell.cell_flags;
  439.       my_cell->cell_refs_to = non_cell.cell_refs_to;
  440.       my_cell->cell_formula = non_cell.cell_formula;
  441.       my_cell->cell_cycle = non_cell.cell_cycle;
  442.       my_cell->cell_font = non_cell.cell_font;
  443.       my_cell->c_z = non_cell.c_z;
  444.       push_refs (my_cell->cell_refs_from);
  445.       if (my_cell->cell_refs_to)
  446.     shift_formula (cur_row, cur_col, rt - non_rf, ct - non_cf);
  447.       my_cell = 0;
  448.       return;
  449.     }
  450.  
  451.   cpf = find_cell (rf, cf);
  452.  
  453.   if (rt == NON_ROW)
  454.     {
  455.       non_rf = rf;
  456.       non_cf = cf;
  457.       if (!cpf)
  458.     bzero (&non_cell, sizeof (non_cell));
  459.       else
  460.     {
  461.       non_cell.cell_flags = cpf->cell_flags;
  462.       non_cell.cell_refs_to = cpf->cell_refs_to;
  463.       non_cell.cell_formula = cpf->cell_formula;
  464.       non_cell.cell_cycle = cpf->cell_cycle;
  465.       non_cell.cell_font = cpf->cell_font;
  466.       non_cell.c_z = cpf->c_z;
  467.       cpf->cell_flags = 0;
  468.       cpf->cell_refs_to = 0;
  469.       cpf->cell_formula = 0;
  470.       cpf->cell_cycle = 0;
  471.       cpf->cell_font = 0;
  472.     }
  473.       return;
  474.     }
  475.  
  476.   cur_row = rt;
  477.   cur_col = ct;
  478.   my_cell = find_cell (cur_row, cur_col);
  479.   if ((!cpf || (!cpf->cell_flags && !cpf->cell_formula && !cpf->cell_font))
  480.       && !my_cell)
  481.     return;
  482.   if (!my_cell)
  483.     {
  484.       my_cell = find_or_make_cell (cur_row, cur_col);
  485.       cpf = find_cell (rf, cf);    /* FOO */
  486.     }
  487.   else
  488.     flush_old_value ();
  489.  
  490.   if (!cpf)
  491.     return;
  492.  
  493.   my_cell->cell_flags = cpf->cell_flags;
  494.   my_cell->cell_refs_to = cpf->cell_refs_to;
  495.   my_cell->cell_formula = cpf->cell_formula;
  496.   my_cell->cell_cycle = cpf->cell_cycle;
  497.   my_cell->cell_font = cpf->cell_font;
  498.   my_cell->c_z = cpf->c_z;
  499.  
  500.   cpf->cell_flags = 0;
  501.   cpf->cell_refs_to = 0;
  502.   cpf->cell_formula = 0;
  503.   cpf->cell_cycle = 0;
  504.   cpf->cell_font = 0;
  505.  
  506.   push_refs (my_cell->cell_refs_from);
  507.   if (my_cell->cell_refs_to)
  508.     shift_formula (cur_row, cur_col, rt - rf, ct - cf);
  509.   my_cell = 0;
  510. }
  511.  
  512. #if __STDC__
  513. void
  514. copy_cell (CELLREF rf, CELLREF cf, CELLREF rt, CELLREF ct)
  515. #else
  516. void
  517. copy_cell (rf, cf, rt, ct)
  518.      CELLREF rf;
  519.      CELLREF cf;
  520.      CELLREF rt;
  521.      CELLREF ct;
  522. #endif
  523. {
  524.   CELL *cpf;
  525.  
  526.   cpf = find_cell (rf, cf);
  527.   cur_row = rt;
  528.   cur_col = ct;
  529.   my_cell = find_cell (cur_row, cur_col);
  530.   if ((!cpf || (!cpf->cell_flags && !cpf->cell_formula && !cpf->cell_font))
  531.       && !my_cell)
  532.     return;
  533.   if (!my_cell)
  534.     {
  535.       my_cell = find_or_make_cell (cur_row, cur_col);
  536.       cpf = find_cell (rf, cf);    /* FOO */
  537.     }
  538.   else
  539.     flush_old_value ();
  540.  
  541.   if (!cpf)
  542.     return;
  543.  
  544.   my_cell->cell_flags = cpf->cell_flags;
  545.   my_cell->cell_cycle = cpf->cell_cycle;
  546.   my_cell->cell_font = cpf->cell_font;
  547.   my_cell->cell_refs_to = cpf->cell_refs_to;
  548.  
  549.   if (my_cell->cell_refs_to)
  550.     my_cell->cell_refs_to->refs_refcnt++;
  551.  
  552.   if (GET_TYP (my_cell) == TYP_STR)
  553.     my_cell->cell_str = strdup (cpf->cell_str);
  554.   else
  555.     my_cell->c_z = cpf->c_z;
  556.  
  557.   if (cpf->cell_formula)
  558.     {
  559.       unsigned char *fp;
  560.       unsigned char *hi;
  561.       unsigned char byte;
  562.       CELLREF trr, tcc;
  563.       struct rng trng;
  564.       struct function *f;
  565.       size_t len;
  566.       struct var *v;
  567.       CELL *tcp;
  568.  
  569.       fp = cpf->cell_formula;
  570.       hi = 0;
  571.       if (!moving)
  572.     moving = init_stack ();
  573.       while ((byte = *fp++) != ENDCOMP)
  574.     {
  575.       if (byte < USR1)
  576.         f = &the_funs[byte];
  577.       else if (byte < SKIP)
  578.         {
  579.           int tmp;
  580. #ifdef TEST
  581.           if (byte - USR1 >= n_usr_funs)
  582.         panic ("Only have %d usr-function slots, but found byte for slot %d", n_usr_funs, 1 + byte - USR1);
  583. #endif
  584.           tmp = *fp++;
  585.           f = &usr_funs[byte - USR1][tmp];
  586.         }
  587.       else
  588.         f = &skip_funs[byte - SKIP];
  589.  
  590.       if (f->fn_argn & X_J)
  591.         fp++;
  592.       else if (f->fn_argn & X_JL)
  593.         fp += 2;
  594.  
  595.       if ((f->fn_argn & X_ARGS) == X_AN)
  596.         fp++;
  597.  
  598.       switch (byte)
  599.         {
  600.         case CONST_FLT:
  601.           fp += sizeof (double);
  602.           break;
  603.  
  604.         case CONST_INT:
  605.           fp += sizeof (long);
  606.           break;
  607.  
  608.         case CONST_STR:
  609.           if (!hi)
  610.         hi = fp + fp[-1];
  611.           break;
  612.  
  613.         case CONST_STR_L:
  614.           if (!hi)
  615.         hi = fp + fp[-2] + ((unsigned) (fp[-1]) << 8);
  616.           break;
  617.  
  618.         case CONST_ERR:
  619.           fp += 1 /* +sizeof(char *) */ ;
  620.           break;
  621.  
  622.         case VAR:
  623.           bcopy (fp, &v, sizeof (struct var *));
  624.           fp += sizeof (struct var *);
  625.           add_ref_fm (&(v->var_ref_fm), cur_row, cur_col);
  626.           switch (v->var_flags)
  627.         {
  628.         case VAR_UNDEF:
  629.           break;
  630.         case VAR_CELL:
  631.           tcp = find_cell (v->v_rng.lr, v->v_rng.lc);
  632.           add_ref_fm (&(tcp->cell_refs_from), cur_row, cur_col);
  633.           break;
  634.         case VAR_RANGE:
  635.           add_range_ref (&(v->v_rng));
  636.           /* sparse array bug fixed here */
  637.           my_cell = find_cell (cur_row, cur_col);
  638.           cpf = find_cell (rf, cf);
  639.           break;
  640.         }
  641.           break;
  642.  
  643.         case R_CELL:
  644.         case R_CELL | COLREL:
  645.         case R_CELL | ROWREL:
  646.         case R_CELL | ROWREL | COLREL:
  647.           push_stack (moving, fp);
  648.           fp += EXP_ADD;
  649.           break;
  650.  
  651.         case RANGE:
  652.         case RANGE | LRREL:
  653.         case RANGE | LRREL | LCREL:
  654.         case RANGE | LRREL | LCREL | HCREL:
  655.         case RANGE | LRREL | HCREL:
  656.         case RANGE | LRREL | HRREL:
  657.         case RANGE | LRREL | HRREL | LCREL:
  658.         case RANGE | LRREL | HRREL | LCREL | HCREL:
  659.         case RANGE | LRREL | HRREL | HCREL:
  660.         case RANGE | HRREL:
  661.         case RANGE | HRREL | LCREL:
  662.         case RANGE | HRREL | LCREL | HCREL:
  663.         case RANGE | HRREL | HCREL:
  664.         case RANGE | LCREL:
  665.         case RANGE | LCREL | HCREL:
  666.         case RANGE | HCREL:
  667.           push_stack (moving, fp);
  668.           fp += EXP_ADD_RNG;
  669.           break;
  670.  
  671.         default:
  672.           break;
  673.         }
  674.     }
  675.       if (!hi)
  676.     hi = fp;
  677.       else
  678.     hi += strlen ((char *) hi);
  679.       hi++;
  680.       len = hi - cpf->cell_formula;
  681.       my_cell->cell_formula = cpf->cell_formula;
  682.       cpf->cell_formula = ck_malloc (hi - cpf->cell_formula);
  683.       bcopy (my_cell->cell_formula, cpf->cell_formula, len);
  684.       while (fp = pop_stack (moving))
  685.     {
  686.       byte = fp[-1];
  687.       if ((byte | ROWREL | COLREL) == (R_CELL | ROWREL | COLREL))
  688.         {
  689.           trr = GET_ROW (fp);
  690.           tcc = GET_COL (fp);
  691.           if (byte & ROWREL)
  692.         {
  693.           trr += rt - rf;
  694.           PUT_ROW (fp, trr);
  695.         }
  696.           if (byte & COLREL)
  697.         {
  698.           tcc += ct - cf;
  699.           PUT_COL (fp, tcc);
  700.         }
  701.           tcp = find_or_make_cell (trr, tcc);
  702.           add_ref_fm (&(tcp->cell_refs_from), cur_row, cur_col);
  703.         }
  704. #ifdef TEST
  705.       else if ((byte | LRREL | HRREL | LCREL | HCREL) !=
  706.            (RANGE | LRREL | HRREL | LCREL | HCREL))
  707.         panic ("Unknown byte %x in copy_cell", byte);
  708. #endif
  709.       else
  710.         {
  711.           GET_RNG (fp, &trng);
  712.           if (byte & LRREL)
  713.         trng.lr += rt - rf;
  714.           if (byte & HRREL)
  715.         trng.hr += rt - rf;
  716.           if (byte & LCREL)
  717.         trng.lc += ct - cf;
  718.           if (byte & HCREL)
  719.         trng.hc += ct - cf;
  720.           PUT_RNG (fp, &trng);
  721.           add_range_ref (&trng);
  722.           /* sparse array bug fixed here */
  723.           my_cell = find_cell (cur_row, cur_col);
  724.           cpf = find_cell (rf, cf);
  725.         }
  726.     }
  727.       update_cell (my_cell);
  728.     }
  729.   else
  730.     {
  731.       my_cell->cell_formula = 0;
  732.     }
  733.   io_pr_cell (cur_row, cur_col, my_cell);
  734.  
  735.   push_refs (my_cell->cell_refs_from);
  736.   my_cell = 0;
  737. }
  738.  
  739. /* Take away the value of CP.  This means getting rid of all the references
  740.    to it, etc.
  741.  */
  742. void
  743. flush_old_value ()
  744. {
  745.   struct ref_to *ref;
  746.   unsigned char *refloc;
  747.   int n;
  748.   unsigned char byte;
  749.   CELL *other_cell;
  750.   struct var *varp;
  751.  
  752.   ref = my_cell->cell_refs_to;
  753.   if (ref)
  754.     {
  755.       for (n = 0; n < ref->refs_used; n++)
  756.     {
  757.       /* Switch on formula[ref->to_refs[n]] */
  758.       refloc = &(my_cell->cell_formula[ref->to_refs[n]]);
  759.       byte = refloc[0];
  760.       switch (byte)
  761.         {
  762.         case F_ROW:
  763.         case F_COL:
  764.           break;
  765.  
  766.         case R_CELL:
  767.         case R_CELL | ROWREL:
  768.         case R_CELL | COLREL:
  769.         case R_CELL | ROWREL | COLREL:
  770.           other_cell = find_cell (GET_ROW (refloc + 1), GET_COL (refloc + 1));
  771.           if (other_cell)
  772.         flush_ref_fm (&(other_cell->cell_refs_from), cur_row, cur_col);
  773. #ifdef TEST
  774.           else
  775.         io_error_msg ("Can't find other_cell in flush_old_value");
  776. #endif
  777.           break;
  778.         case RANGE:
  779.         case RANGE | LRREL:
  780.         case RANGE | LRREL | LCREL:
  781.         case RANGE | LRREL | LCREL | HCREL:
  782.         case RANGE | LRREL | HCREL:
  783.         case RANGE | LRREL | HRREL:
  784.         case RANGE | LRREL | HRREL | LCREL:
  785.         case RANGE | LRREL | HRREL | LCREL | HCREL:
  786.         case RANGE | LRREL | HRREL | HCREL:
  787.         case RANGE | HRREL:
  788.         case RANGE | HRREL | LCREL:
  789.         case RANGE | HRREL | LCREL | HCREL:
  790.         case RANGE | HRREL | HCREL:
  791.         case RANGE | LCREL:
  792.         case RANGE | LCREL | HCREL:
  793.         case RANGE | HCREL:
  794.           {
  795.         struct rng rng;
  796.  
  797.         GET_RNG (refloc + 1, &rng);
  798.         flush_range_ref (&rng, cur_row, cur_col);
  799.           }
  800.           break;
  801.  
  802.         case VAR:
  803.           bcopy (&refloc[1], &varp, sizeof (struct var *));
  804.           flush_ref_fm (&(varp->var_ref_fm), cur_row, cur_col);
  805.           if (varp->var_flags == VAR_CELL)
  806.         {
  807.           other_cell = find_cell (varp->v_rng.lr, varp->v_rng.lc);
  808.           if (other_cell)
  809.             flush_ref_fm (&(other_cell->cell_refs_from), cur_row, cur_col);
  810.         }
  811.           else if (varp->var_flags == VAR_RANGE)
  812.         flush_range_ref (&(varp->v_rng), cur_row, cur_col);
  813. #ifdef TEST
  814.           else if (varp->var_flags != VAR_UNDEF)
  815.         panic ("Unknown var type %d", varp->var_flags);
  816. #endif
  817.           break;
  818.  
  819.         default:
  820.           {
  821.         struct function *fun;
  822.  
  823.         if (byte < USR1)
  824.           fun = &the_funs[byte];
  825. #ifdef TEST
  826.         else if (byte >= SKIP)
  827.           fun = 0, panic ("SKIP? in flush_old_value()");
  828. #endif
  829.         else
  830.           fun = &usr_funs[byte - USR1][refloc[1]];
  831.  
  832.         if (fun->fn_comptype & C_T)
  833.           {
  834. #ifdef TEST
  835.             if (!timer_cells || !timer_cells->refs_used)
  836.               panic ("No timer cells in flush_timer_cell");
  837. #endif
  838.             flush_ref_fm (&timer_cells, cur_row, cur_col);
  839.             if (!timer_cells || timer_cells->refs_used == 0)
  840.               {
  841.             timer_active = 0;
  842.             alarm_active = 0;
  843.               }
  844.             break;
  845.           }
  846.         else
  847.           io_error_msg ("Bad ref_to of %d.%x ignored", ref->to_refs[n], byte);
  848.           }
  849.           break;
  850.         }
  851.     }
  852. #ifdef SPLIT_REFS
  853.       ref->refs_used = 0;
  854. #else
  855.       flush_ref_to (&(my_cell->cell_refs_to));
  856. #endif
  857.     }
  858.   if (my_cell->cell_formula)
  859.     {
  860.       byte_free (my_cell->cell_formula);
  861.       my_cell->cell_formula = 0;
  862.     }
  863.   if (GET_TYP (my_cell) == TYP_STR)
  864.     free (my_cell->cell_str);
  865.   SET_TYP (my_cell, 0);
  866. }
  867.  
  868. /* --------- Routines for dealing with cell references to other cells ------ */
  869.  
  870. #if __STDC__
  871. void
  872. add_ref (CELLREF row, CELLREF col)
  873. #else
  874. void
  875. add_ref (row, col)
  876.      CELLREF row;
  877.      CELLREF col;
  878. #endif
  879. {
  880.   CELL *other_cell;
  881.  
  882.   other_cell = find_or_make_cell (row, col);
  883.   add_ref_fm (&(other_cell->cell_refs_from), cur_row, cur_col);
  884. }
  885.  
  886. void
  887. add_range_ref (rng)
  888.      struct rng *rng;
  889. {
  890.   CELL *other_cell;
  891.   struct ref_fm *oldref, *newref;
  892.   struct ref_fm nonref;
  893.  
  894.  
  895.   make_cells_in_range (rng);
  896.  
  897.   /* Be efficient:  If cells in the range currently have the same
  898.    * references, they'll have the same references afterward, so just
  899.    * adjust the refcounts
  900.    */
  901.   nonref.refs_refcnt = 1;
  902.   other_cell = next_cell_in_range ();
  903.   oldref = other_cell->cell_refs_from;
  904.   if (oldref && oldref->refs_refcnt == 1)
  905.     oldref = &nonref;
  906.  
  907.   add_ref_fm (&(other_cell->cell_refs_from), cur_row, cur_col);
  908.   newref = other_cell->cell_refs_from;
  909.   while (other_cell = next_cell_in_range ())
  910.     {
  911.       if (other_cell->cell_refs_from == oldref)
  912.     {
  913.       if (oldref)
  914.         {
  915.           if (oldref->refs_refcnt == 1)
  916.         {
  917.           flush_fm_ref (oldref);
  918.           oldref = &nonref;
  919.         }
  920.           else
  921.         oldref->refs_refcnt--;
  922.         }
  923.       other_cell->cell_refs_from = newref;
  924.       newref->refs_refcnt++;
  925.     }
  926.       else if (oldref == &nonref && (!other_cell->cell_refs_from || other_cell->cell_refs_from->refs_refcnt > 1))
  927.     {
  928.       oldref = other_cell->cell_refs_from;
  929.       add_ref_fm (&(other_cell->cell_refs_from), cur_row, cur_col);
  930.       newref = other_cell->cell_refs_from;
  931.     }
  932.       else
  933.     add_ref_fm (&(other_cell->cell_refs_from), cur_row, cur_col);
  934.     }
  935.   /* if(oldref && oldref->refs_refcnt==0) {
  936.         oldref->refs_refcnt=1;
  937.         flush_fm_ref(oldref);
  938.     } */
  939. }
  940.  
  941. #if __STDC__
  942. static void
  943. flush_range_ref (struct rng *rng, CELLREF rr, CELLREF cc)
  944. #else
  945. static void
  946. flush_range_ref (rng, rr, cc)
  947.      struct rng *rng;
  948.      CELLREF rr;
  949.      CELLREF cc;
  950. #endif
  951. {
  952.   CELL *other_cell;
  953. #ifndef SPLIT_REFS
  954.   struct ref_fm *oldref, *newref;
  955.   struct ref_fm nonref;
  956. #endif
  957.   /* This is horribly inefficient:  Simply referencing a cell makes
  958.        it appear.  On the other hand, there is no other easy way to deal
  959.        with the references to the cells (That I know of, anyway) */
  960.   find_cells_in_range (rng);
  961. #ifndef SPLIT_REFS
  962.   /* Be efficient:  If cells in the range currently have the same
  963.        references, they'll have the same references afterward, so just
  964.        adjust the refcounts */
  965.   nonref.refs_refcnt = 1;
  966.   other_cell = next_cell_in_range ();
  967.   if (!other_cell)
  968.     return;
  969.   oldref = other_cell->cell_refs_from;
  970.   if (oldref && oldref->refs_refcnt == 1)
  971.     oldref = &nonref;
  972.  
  973.   flush_ref_fm (&(other_cell->cell_refs_from), rr, cc);
  974.   newref = other_cell->cell_refs_from;
  975.   while (other_cell = next_cell_in_range ())
  976.     {
  977.       if (other_cell->cell_refs_from == oldref)
  978.     {
  979.       if (oldref)
  980.         {
  981.           if (oldref->refs_refcnt == 1)
  982.         {
  983.           flush_fm_ref (oldref);
  984.           oldref = &nonref;
  985.         }
  986.           else
  987.         oldref->refs_refcnt--;
  988.         }
  989.       other_cell->cell_refs_from = newref;
  990.       if (newref)
  991.         newref->refs_refcnt++;
  992.     }
  993.       else if (oldref == &nonref && (!other_cell->cell_refs_from || other_cell->cell_refs_from->refs_refcnt > 1))
  994.     {
  995.       oldref = other_cell->cell_refs_from;
  996.       flush_ref_fm (&(other_cell->cell_refs_from), rr, cc);
  997.       newref = other_cell->cell_refs_from;
  998.     }
  999.       else
  1000.     flush_ref_fm (&(other_cell->cell_refs_from), rr, cc);
  1001.     }
  1002. #else
  1003.   while (other_cell = next_cell_in_range ())
  1004.     flush_ref_fm (&(other_cell->cell_refs_from), rr, cc);
  1005. #endif
  1006. }
  1007.  
  1008. /* SPLIT_REFS should probably go away, since it is a performance loss.
  1009.    When it is defined, we allocate a a reference structure for each cell with
  1010.    references, and update them individually.
  1011.  
  1012.    The default is to allocate one reference structure for each *different*
  1013.    reference, and have multiple cells point to it.  We use reference counts
  1014.    to keep track of when to delete the reference structure.  This would
  1015.    appear to be a performance loss, but because of the increased efficiency
  1016.    in referencing ranges, it may actually be faster.  It also uses *far* less
  1017.    memory than SPLIT_REFS */
  1018.  
  1019.  
  1020. #ifndef SPLIT_REFS
  1021. #ifdef __TURBOC__
  1022. #define FM_HASH_NUM 51
  1023. #define TO_HASH_NUM 13
  1024. #else
  1025. #define FM_HASH_NUM 503
  1026. #define TO_HASH_NUM 29
  1027. #endif
  1028. #ifdef TEST
  1029. static int fm_misses = 0;
  1030. static int to_misses = 0;
  1031. #endif
  1032.  
  1033. static struct ref_fm *fm_list[FM_HASH_NUM];
  1034. static struct ref_fm *fm_tmp_ref;
  1035. static unsigned fm_tmp_ref_alloc;
  1036.  
  1037. static struct ref_to *to_list[TO_HASH_NUM];
  1038. static struct ref_to *to_tmp_ref;
  1039. static unsigned to_tmp_ref_alloc;
  1040.  
  1041. void
  1042. flush_refs ()
  1043. {
  1044.   int n;
  1045.   struct ref_fm *ftmp, *oftmp;
  1046.   struct ref_to *ttmp, *ottmp;
  1047.  
  1048.   for (n = 0; n < FM_HASH_NUM; n++)
  1049.     {
  1050.       for (ftmp = fm_list[n]; ftmp; ftmp = oftmp)
  1051.     {
  1052.       oftmp = ftmp->refs_next;
  1053.       free (ftmp);
  1054.     }
  1055.       fm_list[n] = 0;
  1056.     }
  1057.   for (n = 0; n < TO_HASH_NUM; n++)
  1058.     {
  1059.       for (ttmp = to_list[n]; ttmp; ttmp = ottmp)
  1060.     {
  1061.       ottmp = ttmp->refs_next;
  1062.       free (ttmp);
  1063.     }
  1064.       to_list[n] = 0;
  1065.     }
  1066. }
  1067.  
  1068. static struct ref_fm *
  1069. find_fm_ref ()
  1070. {
  1071.   struct ref_fm *tmp;
  1072.   int n;
  1073.   unsigned long hash;
  1074.  
  1075. #if 1
  1076.   for (hash = 0, n = 0; n < fm_tmp_ref->refs_used; n++)
  1077.     {
  1078.       hash += (n + 1) * (((fm_tmp_ref->fm_refs[n].ref_row) << BITS_PER_CELLREF) +
  1079.              fm_tmp_ref->fm_refs[n].ref_col);
  1080.     }
  1081.   hash %= FM_HASH_NUM;
  1082. #else
  1083.   hash = fm_tmp_ref->refs_used;
  1084. #endif
  1085.   for (tmp = fm_list[hash]; tmp; tmp = tmp->refs_next)
  1086.     {
  1087.       if (tmp->refs_used != fm_tmp_ref->refs_used)
  1088.     continue;
  1089.       if (!bcmp (tmp->fm_refs, fm_tmp_ref->fm_refs, fm_tmp_ref->refs_used * sizeof (struct ref_array)))
  1090.     {
  1091.       tmp->refs_refcnt++;
  1092.       return tmp;
  1093.     }
  1094. #ifdef TEST
  1095.       else
  1096.     fm_misses++;
  1097. #endif
  1098.     }
  1099.  
  1100.   tmp = ck_malloc (sizeof (struct ref_fm) + (fm_tmp_ref->refs_used - 1) * sizeof (struct ref_array));
  1101.   tmp->refs_next = fm_list[hash];
  1102.   fm_list[hash] = tmp;
  1103.   tmp->refs_refcnt = 1;
  1104.   tmp->refs_used = fm_tmp_ref->refs_used;
  1105.   bcopy (fm_tmp_ref->fm_refs, tmp->fm_refs, tmp->refs_used * sizeof (struct ref_array));
  1106.  
  1107.   return tmp;
  1108. }
  1109.  
  1110. static void 
  1111. flush_fm_ref (old)
  1112.      struct ref_fm *old;
  1113. {
  1114.   struct ref_fm *tmp;
  1115.   int n;
  1116.   unsigned long hash;
  1117.  
  1118.   --(old->refs_refcnt);
  1119.  
  1120. #ifdef DEFER_FREE
  1121.   return;
  1122. #endif
  1123.   if (!old->refs_refcnt)
  1124.     {
  1125. #if 1
  1126.       for (hash = 0, n = 0; n < old->refs_used; n++)
  1127.     {
  1128.       hash += (n + 1) * (((old->fm_refs[n].ref_row) << BITS_PER_CELLREF) +
  1129.                  old->fm_refs[n].ref_col);
  1130.     }
  1131.       hash %= FM_HASH_NUM;
  1132. #else
  1133.       hash = old->refs_used;
  1134. #endif
  1135.       if (fm_list[hash] == old)
  1136.     fm_list[hash] = old->refs_next;
  1137.       else
  1138.     {
  1139.       for (tmp = fm_list[hash]; tmp && tmp->refs_next != old; tmp = tmp->refs_next)
  1140.         ;
  1141. #ifdef TEST
  1142.       if (!tmp)
  1143.         {
  1144.           io_error_msg ("Old not in refs_list in flush_fm_ref(%p)", old);
  1145.           return;
  1146.         }
  1147. #endif
  1148.       tmp->refs_next = old->refs_next;
  1149.     }
  1150.       free (old);
  1151.     }
  1152. }
  1153.  
  1154. /* This adds a from reference to a cells reference list.
  1155.  * Note that the ref_fm structures themselves are hash-consed.
  1156.  */
  1157. #if __STDC__
  1158. static void
  1159. add_ref_fm (struct ref_fm **where, CELLREF r, CELLREF c)
  1160. #else
  1161. static void
  1162. add_ref_fm (where, r, c)
  1163.      struct ref_fm **where;
  1164.      CELLREF r;
  1165.      CELLREF c;
  1166. #endif
  1167. {
  1168.   struct ref_fm *from;
  1169.   int n;
  1170.  
  1171.   from = *where;
  1172.   if (!from)
  1173.     {
  1174.       if (!fm_tmp_ref)
  1175.     {
  1176.       fm_tmp_ref = ck_malloc (sizeof (struct ref_fm));
  1177.       fm_tmp_ref_alloc = 1;
  1178.     }
  1179.       fm_tmp_ref->refs_used = 1;
  1180.       fm_tmp_ref->fm_refs[0].ref_row = r;
  1181.       fm_tmp_ref->fm_refs[0].ref_col = c;
  1182.     }
  1183.   else
  1184.     {
  1185.       if (fm_tmp_ref_alloc <= from->refs_used)
  1186.     {
  1187.       fm_tmp_ref =
  1188.         ck_realloc (fm_tmp_ref, sizeof (struct ref_fm)
  1189.             + from->refs_used * sizeof (struct ref_array)) ;
  1190.       fm_tmp_ref_alloc = from->refs_used + 1;
  1191.     }
  1192.       fm_tmp_ref->refs_used = from->refs_used + 1;
  1193.       n = 0;
  1194.       while (n < from->refs_used
  1195.          && (from->fm_refs[n].ref_row < r
  1196.        || (from->fm_refs[n].ref_row == r && from->fm_refs[n].ref_col <= c)))
  1197.     {
  1198.       fm_tmp_ref->fm_refs[n] = from->fm_refs[n];
  1199.       n++;
  1200.     }
  1201.       fm_tmp_ref->fm_refs[n].ref_row = r;
  1202.       fm_tmp_ref->fm_refs[n].ref_col = c;
  1203.       while (n < from->refs_used)
  1204.     {
  1205.       fm_tmp_ref->fm_refs[n + 1] = from->fm_refs[n];
  1206.       n++;
  1207.     }
  1208.     }
  1209.   *where = find_fm_ref ();
  1210.   if (from)
  1211.     flush_fm_ref (from);
  1212. }
  1213.  
  1214. #if __STDC__
  1215. static void
  1216. flush_ref_fm (struct ref_fm **where, CELLREF r, CELLREF c)
  1217. #else
  1218. static void
  1219. flush_ref_fm (where, r, c)
  1220.      struct ref_fm **where;
  1221.      CELLREF r;
  1222.      CELLREF c;
  1223. #endif
  1224. {
  1225.   struct ref_fm *from;
  1226.   int n;
  1227.  
  1228.   from = *where;
  1229. #ifdef TEST
  1230.   if (!from)
  1231.     {
  1232.       io_error_msg ("No refs in flush_ref_fm(%p,%u,%u)", where, r, c);
  1233.       return;
  1234.     }
  1235. #endif
  1236.   if (!from)
  1237.     return;
  1238.   if (from->refs_used == 1)
  1239.     {
  1240.       *where = 0;
  1241.       flush_fm_ref (from);
  1242.       return;
  1243.     }
  1244.   fm_tmp_ref->refs_used = from->refs_used - 1;
  1245.   n = 0;
  1246.   while (n < from->refs_used
  1247.      && (from->fm_refs[n].ref_row < r
  1248.     || (from->fm_refs[n].ref_row == r && from->fm_refs[n].ref_col < c)))
  1249.     {
  1250.       fm_tmp_ref->fm_refs[n] = from->fm_refs[n];
  1251.       n++;
  1252.     }
  1253. #ifdef TEST
  1254.   if (n == from->refs_used)
  1255.     {
  1256.       io_error_msg ("No refs from %u,%u in %p in flush_refs_fm", r, c, where);
  1257.       return;
  1258.     }
  1259. #endif
  1260.   while (n < fm_tmp_ref->refs_used)
  1261.     {
  1262.       fm_tmp_ref->fm_refs[n] = from->fm_refs[n + 1];
  1263.       n++;
  1264.     }
  1265.   *where = find_fm_ref ();
  1266.   flush_fm_ref (from);
  1267. }
  1268.  
  1269. #ifdef TEST
  1270.  
  1271. void
  1272. dbg_print_ref_fm (rf)
  1273.      struct ref_fm *rf;
  1274. {
  1275.   int nr;
  1276.   char *bufp;
  1277.  
  1278.   if (rf)
  1279.     {
  1280.       io_text_line ("fm %p: refcnt %u  next %p  used %u",
  1281.             rf, rf->refs_refcnt, rf->refs_next, rf->refs_used);
  1282.       for (nr = 0, bufp = print_buf; nr < rf->refs_used; nr++)
  1283.     {
  1284.       (void) sprintf (bufp, " %s", cell_name (rf->fm_refs[nr].ref_row, rf->fm_refs[nr].ref_col));
  1285.       if (nr % 10 == 9)
  1286.         {
  1287.           io_text_line (print_buf);
  1288.           bufp = print_buf;
  1289.         }
  1290.       else
  1291.         bufp += strlen (bufp);
  1292.     }
  1293.       if (nr % 10)
  1294.     io_text_line (print_buf);
  1295.     }
  1296. }
  1297.  
  1298. #endif
  1299.  
  1300. static struct ref_to *
  1301. find_to_ref ()
  1302. {
  1303.   struct ref_to *tmp;
  1304.   int n;
  1305.   unsigned long hash;
  1306.  
  1307.   /* io_error_msg("find_to_ref %u %u",to_tmp_ref->refs_used,to_tmp_ref->to_refs[0]); */
  1308. #if 1
  1309.   for (hash = 0, n = 0; n < to_tmp_ref->refs_used; n++)
  1310.     hash += (n + 1) * to_tmp_ref->to_refs[n];
  1311.  
  1312.   hash %= TO_HASH_NUM;
  1313. #else
  1314.   hash = to_tmp_ref->refs_used;
  1315. #endif
  1316.   for (tmp = to_list[hash]; tmp; tmp = tmp->refs_next)
  1317.     {
  1318.       /* io_error_msg("%p(%u)->%p  %u %u",tmp,tmp->refs_refcnt,
  1319.             tmp->refs_next,tmp->refs_used,tmp->to_refs[0]); */
  1320.       if (tmp->refs_used != to_tmp_ref->refs_used)
  1321.     continue;
  1322.       if (!bcmp (tmp->to_refs, to_tmp_ref->to_refs, to_tmp_ref->refs_used))
  1323.     {
  1324.       /* io_error_msg("Hit!"); */
  1325.       tmp->refs_refcnt++;
  1326.       return tmp;
  1327.     }
  1328. #ifdef TEST
  1329.       else
  1330.     to_misses++;
  1331. #endif
  1332.     }
  1333.  
  1334.   /* io_error_msg("Miss. .."); */
  1335.   tmp = ck_malloc (sizeof (struct ref_to) + to_tmp_ref->refs_used - 1);
  1336.   tmp->refs_next = to_list[hash];
  1337.   to_list[hash] = tmp;
  1338.   tmp->refs_refcnt = 1;
  1339.   tmp->refs_used = to_tmp_ref->refs_used;
  1340.   bcopy (to_tmp_ref->to_refs, tmp->to_refs, tmp->refs_used);
  1341.  
  1342.   return tmp;
  1343. }
  1344.  
  1345. void
  1346. add_ref_to (whereto)
  1347.      int whereto;
  1348. {
  1349.   struct ref_to *from;
  1350.   int n;
  1351.  
  1352.   from = my_cell->cell_refs_to;
  1353.   if (!from)
  1354.     {
  1355.       if (!to_tmp_ref)
  1356.     {
  1357.       to_tmp_ref = ck_malloc (sizeof (struct ref_to));
  1358.       to_tmp_ref_alloc = 1;
  1359.     }
  1360.       to_tmp_ref->refs_used = 1;
  1361.       to_tmp_ref->to_refs[0] = whereto;
  1362.     }
  1363.   else
  1364.     {
  1365.       if (to_tmp_ref_alloc <= from->refs_used)
  1366.     {
  1367.       to_tmp_ref = ck_realloc (to_tmp_ref, sizeof (struct ref_to) + from->refs_used);
  1368.       to_tmp_ref_alloc = from->refs_used + 1;
  1369.     }
  1370.       to_tmp_ref->refs_used = from->refs_used + 1;
  1371.       n = 0;
  1372.       while (n < from->refs_used && from->to_refs[n] < whereto)
  1373.     {
  1374.       to_tmp_ref->to_refs[n] = from->to_refs[n];
  1375.       n++;
  1376.     }
  1377.       to_tmp_ref->to_refs[n] = whereto;
  1378.       while (n < from->refs_used)
  1379.     {
  1380.       to_tmp_ref->to_refs[n + 1] = from->to_refs[n];
  1381.       n++;
  1382.     }
  1383.       flush_ref_to (&(my_cell->cell_refs_to));
  1384.     }
  1385.   my_cell->cell_refs_to = find_to_ref ();
  1386. }
  1387.  
  1388. static void
  1389. flush_ref_to (where)
  1390.      struct ref_to **where;
  1391. {
  1392.   struct ref_to *tmp;
  1393.   struct ref_to *old;
  1394.   int n;
  1395.   unsigned long hash;
  1396.  
  1397. #ifdef TEST
  1398.   if (!where || !*where)
  1399.     {
  1400.       io_error_msg ("null flush_ref_to(%p)", where);
  1401.       return;
  1402.     }
  1403. #endif
  1404.   old = *where;
  1405.   *where = 0;
  1406.   --(old->refs_refcnt);
  1407.  
  1408. #ifdef DEFER_FREE
  1409.   return;
  1410. #endif
  1411.   if (!old->refs_refcnt)
  1412.     {
  1413. #if 1
  1414.       for (hash = 0, n = 0; n < old->refs_used; n++)
  1415.     hash += (n + 1) * old->to_refs[n];
  1416.  
  1417.       hash %= TO_HASH_NUM;
  1418. #else
  1419.       hash = old->refs_used;
  1420. #endif
  1421.       if (to_list[hash] == old)
  1422.     to_list[hash] = old->refs_next;
  1423.       else
  1424.     {
  1425.       for (tmp = to_list[hash]; tmp && tmp->refs_next != old; tmp = tmp->refs_next)
  1426.         ;
  1427. #ifdef TEST
  1428.       if (!tmp)
  1429.         {
  1430.           io_error_msg ("Old not in refs_list in flush_to_ref(%p)", old);
  1431.           return;
  1432.         }
  1433. #endif
  1434.       tmp->refs_next = old->refs_next;
  1435.     }
  1436.       free (old);
  1437.     }
  1438. }
  1439.  
  1440. #ifdef TEST
  1441. void
  1442. dbg_print_ref_to (rt, form)
  1443.      struct ref_to *rt;
  1444.      unsigned char *form;
  1445. {
  1446.   int nr;
  1447.   char *bufp;
  1448.  
  1449.   if (rt)
  1450.     {
  1451.       io_text_line ("to %p: refcnt %u  next %p  used %u",
  1452.             rt, rt->refs_refcnt, rt->refs_next, rt->refs_used);
  1453.       for (nr = 0, bufp = print_buf; nr < rt->refs_used; nr++)
  1454.     {
  1455.       (void) sprintf (bufp, " %3d (%#4x)", rt->to_refs[nr], form[rt->to_refs[nr]]);
  1456.       if (nr % 7 == 6)
  1457.         {
  1458.           io_text_line (print_buf);
  1459.           bufp = print_buf;
  1460.         }
  1461.       else
  1462.         bufp += strlen (bufp);
  1463.     }
  1464.       if (nr % 7)
  1465.     io_text_line (print_buf);
  1466.     }
  1467. }
  1468.  
  1469. void
  1470. ref_stats ()
  1471. {
  1472.   int n;
  1473.   int cur;
  1474.   struct ref_fm *rf;
  1475.   struct ref_to *rt;
  1476.  
  1477.   int rf_max = 0;
  1478.   int rf_num = 0;
  1479.   int rf_shared = 0;
  1480.   int rf_saved = 0;
  1481.   int rf_zero = 0;
  1482.  
  1483.   int rt_max = 0;
  1484.   int rt_num = 0;
  1485.   int rt_shared = 0;
  1486.   int rt_saved = 0;
  1487.   int rt_zero = 0;
  1488.  
  1489.   for (n = 0; n < FM_HASH_NUM; n++)
  1490.     {
  1491.       cur = 0;
  1492.       for (rf = fm_list[n]; rf; rf = rf->refs_next)
  1493.     {
  1494.       if (rf->refs_refcnt == 0)
  1495.         rf_zero++;
  1496.       if (rf->refs_refcnt > 1)
  1497.         {
  1498.           rf_shared++;
  1499.           rf_saved += rf->refs_refcnt - 1;
  1500.         }
  1501.       rf_num++;
  1502.       cur++;
  1503.     }
  1504.       if (cur > rf_max)
  1505.     rf_max = cur;
  1506.     }
  1507.   for (n = 0; n < TO_HASH_NUM; n++)
  1508.     {
  1509.       cur = 0;
  1510.       for (rt = to_list[n]; rt; rt = rt->refs_next)
  1511.     {
  1512.       if (rt->refs_refcnt == 0)
  1513.         rt_zero++;
  1514.       if (rt->refs_refcnt > 1)
  1515.         {
  1516.           rt_shared++;
  1517.           rt_saved += rt->refs_refcnt - 1;
  1518.         }
  1519.       rt_num++;
  1520.       cur++;
  1521.     }
  1522.       if (cur > rt_max)
  1523.     rt_max = cur;
  1524.     }
  1525.   io_text_line ("from: %d refs, max_length %d, shared %d, saved %d, zero_ref %d, missed %d\n", rf_num, rf_max, rf_shared, rf_saved, rf_zero, fm_misses);
  1526.   io_text_line ("to: %d refs, max_length %d, shared %d, saved %d, zero_ref %d, missed %d\n", rt_num, rt_max, rt_shared, rt_saved, rt_zero, to_misses);
  1527. }
  1528.  
  1529. #endif
  1530. #else
  1531.  
  1532. static void
  1533. add_ref_fm (where, r, c)
  1534.      struct ref_fm **where;
  1535.      CELLREF r;
  1536.      CELLREF c;
  1537. {
  1538.   struct ref_fm *ref;
  1539.  
  1540.   ref = *where;
  1541.   if (!ref)
  1542.     {
  1543.       *where = ref = ck_malloc (sizeof (struct ref_fm) + (REF_START - 1) * sizeof (struct ref_array));
  1544.       ref->refs_alloc = REF_START;
  1545.       ref->refs_used = 0;
  1546.     }
  1547.   else if (ref->refs_alloc == ref->refs_used)
  1548.     {
  1549.       ref->refs_alloc REF_INC;
  1550.       *where = ref = ck_realloc (ref, sizeof (struct ref_fm) + (ref->refs_alloc - 1) * sizeof (struct ref_array));
  1551.     }
  1552.   ref->fm_refs[ref->refs_used].ref_row = r;
  1553.   ref->fm_refs[ref->refs_used].ref_col = c;
  1554.   ref->refs_used++;
  1555. }
  1556.  
  1557. static void
  1558. flush_ref_fm (where, r, c)
  1559.      struct ref_fm **where;
  1560.      CELLREF r;
  1561.      CELLREF c;
  1562. {
  1563.   int n;
  1564.   struct ref_fm *ref;
  1565.  
  1566.   ref = *where;
  1567. #ifdef TEST
  1568.   if (!ref)
  1569.     {
  1570.       io_error_msg ("%s->No refs in flush_ref_fm(%d,%d)", cell_name (cur_row, cur_col), r, c);
  1571.       return;
  1572.     }
  1573. #endif
  1574.   for (n = 0; n < ref->refs_used; n++)
  1575.     if (ref->fm_refs[n].ref_row == r && ref->fm_refs[n].ref_col == c)
  1576.       {
  1577.     ref->fm_refs[n] = ref->fm_refs[ref->refs_used - 1];
  1578.     --(ref->refs_used);
  1579.     return;
  1580.       }
  1581. #ifdef TEST
  1582.   io_error_msg ("%s->Can't flush_ref_fm(%d,%d)", cell_name (cur_row, cur_col), r, c);
  1583.   return;
  1584. #endif
  1585. }
  1586.  
  1587. void
  1588. add_ref_to (whereto)
  1589.      int whereto;
  1590. {
  1591.   struct ref_to *ref;
  1592.  
  1593.   ref = my_cell->cell_refs_to;
  1594.   if (!ref)
  1595.     {
  1596.       my_cell->cell_refs_to = ref = ck_malloc (sizeof (struct ref_to) + (REF_START - 1) * sizeof (unsigned char));
  1597.       ref->refs_alloc = REF_START;
  1598.       ref->refs_used = 0;
  1599.     }
  1600.   else if (ref->refs_alloc == ref->refs_used)
  1601.     {
  1602.       ref->refs_alloc REF_INC;
  1603.       my_cell->cell_refs_to = ref = ck_realloc (ref, sizeof (struct ref_to) +
  1604.                 (ref->refs_alloc - 1) * sizeof (unsigned char));
  1605.     }
  1606.   ref->to_refs[ref->refs_used] = whereto;
  1607.   ref->refs_used++;
  1608. }
  1609.  
  1610. #ifdef TEST
  1611.  
  1612. void
  1613. dbg_print_ref_fm (rf)
  1614.      struct ref_fm *rf;
  1615. {
  1616.   int nr;
  1617.   char *bufp;
  1618.  
  1619.   if (rf)
  1620.     {
  1621.       io_text_line ("fm %p: alloc %u  used %u",
  1622.             rf, rf->refs_alloc, rf->refs_used);
  1623.       for (nr = 0, bufp = print_buf; nr < rf->refs_used; nr++)
  1624.     {
  1625.       (void) sprintf (bufp, " %s", cell_name (rf->fm_refs[nr].ref_row, rf->fm_refs[nr].ref_col));
  1626.       if (nr % 10 == 9)
  1627.         {
  1628.           io_text_line (print_buf);
  1629.           bufp = print_buf;
  1630.         }
  1631.       else
  1632.         bufp += strlen (bufp);
  1633.     }
  1634.       if (nr % 10)
  1635.     io_text_line (print_buf);
  1636.     }
  1637. }
  1638.  
  1639. void
  1640. dbg_print_ref_to (rt, form)
  1641.      struct ref_to *rt;
  1642.      unsigned char *form;
  1643. {
  1644.   int nr;
  1645.   char *bufp;
  1646.  
  1647.   if (rt)
  1648.     {
  1649.       io_text_line ("to %p:  alloc %u  used %u",
  1650.             rt, rt->refs_alloc, rt->refs_used);
  1651.       for (nr = 0, bufp = print_buf; nr < rt->refs_used; nr++)
  1652.     {
  1653.       (void) sprintf (bufp, " %3d (%#4x)", rt->to_refs[nr], form[rt->to_refs[nr]]);
  1654.       if (nr % 7 == 6)
  1655.         {
  1656.           io_text_line (print_buf);
  1657.           bufp = print_buf;
  1658.         }
  1659.       else
  1660.         bufp += strlen (bufp);
  1661.     }
  1662.       if (nr % 7)
  1663.     io_text_line (print_buf);
  1664.     }
  1665. }
  1666.  
  1667. void
  1668. ref_stats ()
  1669. {
  1670.   CELL *cp;
  1671.  
  1672.   int rf_num = 0;
  1673.   int rf_zero = 0;
  1674.   int rf_biggest = 0;
  1675.  
  1676.   int rt_num = 0;
  1677.   int rt_zero = 0;
  1678.   int rt_biggest = 0;
  1679.  
  1680.   find_cells_in_range (&all_rng);
  1681.   while (cp = next_cell_in_range ())
  1682.     {
  1683.       if (cp->cell_refs_from)
  1684.     {
  1685.       if (cp->cell_refs_from->refs_used > rf_biggest)
  1686.         rf_biggest = cp->cell_refs_from->refs_used;
  1687.       if (cp->cell_refs_from->refs_used == 0)
  1688.         rf_zero++;
  1689.       rf_num++;
  1690.     }
  1691.       if (cp->cell_refs_to)
  1692.     {
  1693.       if (cp->cell_refs_to->refs_used > rt_biggest)
  1694.         rt_biggest = cp->cell_refs_to->refs_used;
  1695.       if (cp->cell_refs_to->refs_used == 0)
  1696.         rt_zero++;
  1697.       rt_num++;
  1698.     }
  1699.     }
  1700.   io_text_line ("from: %d refs, biggest %d, zero_ref %d\n", rf_num, rf_biggest, rf_zero);
  1701.   io_text_line ("to: %d refs, biggest %d,zero_ref %d\n", rt_num, rt_biggest, rt_zero);
  1702. }
  1703.  
  1704. #endif
  1705.  
  1706. #endif
  1707.  
  1708. /* ------------- Routines for dealing with moving cells -------------------- */
  1709.  
  1710. static struct rng *shift_fm;
  1711. static int shift_ov;
  1712. static int shift_dn;
  1713.  
  1714. static void 
  1715. shift_var (name, v)
  1716.      char *name;
  1717.      struct var *v;
  1718. {
  1719.   int n;
  1720.   int nn;
  1721.  
  1722.  
  1723.   n = (BETWEEN (v->v_rng.hc, shift_fm->lc, shift_fm->hc) << 3)
  1724.     + (BETWEEN (v->v_rng.lc, shift_fm->lc, shift_fm->hc) << 2)
  1725.     + (BETWEEN (v->v_rng.hr, shift_fm->lr, shift_fm->hr) << 1)
  1726.     + BETWEEN (v->v_rng.lr, shift_fm->lr, shift_fm->hr);
  1727.   switch (n)
  1728.     {
  1729.     case 0:
  1730.     case 1:
  1731.     case 2:
  1732.     case 3:
  1733.     case 4:
  1734.     case 8:
  1735.     case 12:
  1736.       /* Null intersection, ignore it */
  1737.       break;
  1738.  
  1739.     case 5:            /* The bottom and right */
  1740.     case 6:            /* The bottom and left */
  1741.     case 9:            /* The top and right */
  1742.     case 10:            /* The top and left */
  1743.       /* The var sticks out of the range we're moving */
  1744.       /* on two sides.  what should we do? */
  1745.       io_error_msg ("'%s' can't be adjusted", v->var_name);
  1746.       break;
  1747.  
  1748.     case 7:            /* v->hc sticks out the right */
  1749.     case 11:            /* v->lc sticks out the left */
  1750.     case 13:            /* v->hr sticks out the bottom */
  1751.     case 14:            /* v->lr sticks out the top */
  1752.       /* It only sticks out on one side.  We can
  1753.            (try to) adjust it */
  1754. #if 0
  1755.       io_error_msg ("'%s' sticks out; adjusted", v->var_name);
  1756. #endif
  1757.     case 15:            /* var is completely inside the range */
  1758.       if (v->var_ref_fm)
  1759.     {
  1760.       for (nn = 0; nn < v->var_ref_fm->refs_used; nn++)
  1761.         {
  1762.           flush_range_ref (&(v->v_rng),
  1763.                    v->var_ref_fm->fm_refs[nn].ref_row,
  1764.                    v->var_ref_fm->fm_refs[nn].ref_col);
  1765.         }
  1766.     }
  1767.       if (n != 7)
  1768.     v->v_rng.hc += shift_ov;
  1769.       if (n != 11)
  1770.     v->v_rng.lc += shift_ov;
  1771.       if (n != 13)
  1772.     v->v_rng.hr += shift_dn;
  1773.       if (n != 14)
  1774.     v->v_rng.lr += shift_dn;
  1775.       if (!v->var_ref_fm)
  1776.     return;
  1777.  
  1778.       for (n = 0; n < v->var_ref_fm->refs_used; n++)
  1779.     {
  1780.       cur_row = v->var_ref_fm->fm_refs[n].ref_row;
  1781.       cur_col = v->var_ref_fm->fm_refs[n].ref_col;
  1782.       add_range_ref (&(v->v_rng));
  1783.       if (my_cell)
  1784.         panic ("shift_outside: my_cell lost.");
  1785.       /* If this panic occurs, the caller should be recomputing
  1786.        * my_cell after shift_outside returns (and this useful panic
  1787.        * will have to be removed or my_cell set temporarily to 0).
  1788.        */
  1789.     }
  1790.       break;
  1791. #ifdef TEST
  1792.     default:
  1793.       panic ("Bad ###%d", n);
  1794. #endif
  1795.     }
  1796. }
  1797. #define RIGHT    8
  1798. #define LEFT    4
  1799. #define BOTTOM    2
  1800. #define TOP    1
  1801.  
  1802. /*
  1803.  * This iterates over the region FM, preparing the cells there to be shifted
  1804.  * OV(er) and D(ow)N.
  1805.  *
  1806.  * After this, the ref_fm and ref_to lists of a cell within the region should
  1807.  * be appropriate to the location that cell will be shifted to.
  1808.  * 
  1809.  * Variables and references to variables are also shifted.
  1810.  */
  1811. void
  1812. shift_outside (fm, dn, ov)
  1813.      struct rng *fm;
  1814.      int dn;
  1815.      int ov;
  1816. {
  1817.   CELL *cp;
  1818.   CELL *fcp;
  1819.   CELL *tcp;
  1820.   int n;
  1821.   int fn;
  1822.   CELLREF rr, cc;
  1823.   CELLREF frr, fcc;
  1824.   CELLREF trr, tcc;
  1825.   unsigned char *ffp;
  1826.   unsigned char *fp;
  1827.   struct var *v;
  1828.   struct rng orng;
  1829.  
  1830.   char *ptr;
  1831.   unsigned long val;
  1832.   static char DEF_REF[] = "DEFREF";
  1833.   static char DEF_RNG[] = "DEFRNG";
  1834.  
  1835.   /* Variables and references to variables are also shifted. */
  1836.   shift_fm = fm;
  1837.   shift_dn = dn;
  1838.   shift_ov = ov;
  1839.   for_all_vars (shift_var);
  1840.  
  1841.   /* This stack is used to defer adjustments to references that are entirely 
  1842.    * within FM.  Intra-FM references are adjusted after references into and
  1843.    * out of FM.
  1844.    */
  1845.  
  1846.   if (!moving)
  1847.     moving = init_stack ();
  1848.  
  1849.   find_cells_in_range (fm);
  1850.  
  1851.   while (cp = next_row_col_in_range (&rr, &cc))
  1852.     {
  1853.       /* cp/rr/cc is a cell in FM. */
  1854.  
  1855.       /* First, adjust references FROM the region */
  1856.       if (cp->cell_refs_to)
  1857.     {
  1858.       for (n = 0; n < cp->cell_refs_to->refs_used; n++)
  1859.         {
  1860.           fp = &(cp->cell_formula[cp->cell_refs_to->to_refs[n]]);
  1861.           switch (*fp)
  1862.         {
  1863.         case R_CELL:
  1864.         case R_CELL | ROWREL:
  1865.         case R_CELL | COLREL:
  1866.         case R_CELL | ROWREL | COLREL:
  1867.           /* Trr/cc/cp is the cell being referenced */
  1868.           trr = GET_ROW (fp + 1);
  1869.           tcc = GET_COL (fp + 1);
  1870.           tcp = find_cell (trr, tcc);
  1871.  
  1872.           /* Get rid of the backpointer to this reference. */
  1873.           flush_ref_fm (&(tcp->cell_refs_from), rr, cc);
  1874.  
  1875.           /* frr/fcc is the new address of the referenced cell.
  1876.            * The address will change if Trr/cc happens to be 
  1877.               * in the region that is moving, or if the reference
  1878.            * is a relative reference.
  1879.            */
  1880.           fn = (BETWEEN (trr, fm->lr, fm->hr)
  1881.             && BETWEEN (tcc, fm->lc, fm->hc)); 
  1882.           frr = (fn || (((*fp) & ROWREL))) ? trr + dn : trr;
  1883.           fcc = (fn || (((*fp) & COLREL))) ? tcc + ov : tcc;
  1884.  
  1885.           PUT_ROW (fp + 1, frr); /* Adjust the formula byte-code. */
  1886.           PUT_COL (fp + 1, fcc); /* This might even be a noop. */
  1887.  
  1888.           /* Reinstall the backreference, unless the new address of the
  1889.            * referenced cell is w/in the region being moved. (In which
  1890.            * case, defer making the backreference).
  1891.            */
  1892.           if (BETWEEN(frr, fm->lr, fm->hr) && BETWEEN(fcc, fm->lc, fm->hc))
  1893.             {
  1894.               push_stack (moving, (VOIDSTAR) TO_MAGIC (rr + dn, cc + ov));
  1895.               push_stack (moving, (VOIDSTAR) TO_MAGIC (frr, fcc));
  1896.               push_stack (moving, DEF_REF);
  1897.             }
  1898.           else
  1899.             {
  1900.               tcp = find_or_make_cell (frr, fcc);
  1901.               add_ref_fm (&(tcp->cell_refs_from), rr + dn, cc + ov);
  1902.               cp = find_cell (rr, cc);
  1903.             }
  1904.  
  1905.           break;
  1906.  
  1907.         case RANGE:
  1908.         case RANGE | LRREL:
  1909.         case RANGE | HRREL:
  1910.         case RANGE | LCREL:
  1911.         case RANGE | HCREL:
  1912.         case RANGE | LRREL | HRREL:
  1913.         case RANGE | LRREL | LCREL:
  1914.         case RANGE | LRREL | HCREL:
  1915.         case RANGE | HRREL | LCREL:
  1916.         case RANGE | HRREL | HCREL:
  1917.         case RANGE | LCREL | HCREL:
  1918.         case RANGE | LRREL | LCREL | HCREL:
  1919.         case RANGE | LRREL | HRREL | LCREL:
  1920.         case RANGE | LRREL | HRREL | HCREL:
  1921.         case RANGE | HRREL | LCREL | HCREL:
  1922.         case RANGE | LRREL | HRREL | LCREL | HCREL:
  1923.           /* orng is the range being referenced. */
  1924.           GET_RNG (fp + 1, &orng);
  1925.  
  1926.           /* Get rid of backpointers to this reference. */
  1927.           flush_range_ref (&orng, rr, cc);
  1928.  
  1929.                   /* This asks -- does the referenced region
  1930.                       * intersect the region being moved at the: 
  1931.                    */
  1932.           fn = ((BETWEEN (orng.hc, fm->lc, fm->hc) << 3)   /* right?  8 */
  1933.                | (BETWEEN (orng.lc, fm->lc, fm->hc) << 2)  /* left?   4 */
  1934.                | (BETWEEN (orng.hr, fm->lr, fm->hr) << 1)  /* bottom? 2 */
  1935.                | BETWEEN (orng.lr, fm->lr, fm->hr));       /* top?    1 */
  1936.  
  1937.           /* In this switch, a union of masks represents a conjunction 
  1938.            * of intersections.  So, LEFT | TOP means `interects at left
  1939.            * and top'. 
  1940.            */
  1941.           switch (fn)
  1942.             {
  1943.               /* Most of the time, the referenced region is moved only
  1944.                * if the reference is relative.
  1945.                    */
  1946.             case LEFT | TOP:
  1947.             case LEFT | BOTTOM:
  1948.             case RIGHT | TOP:
  1949.             case RIGHT | BOTTOM:
  1950.  
  1951.               /* There used to be a warning given to the user here, but
  1952.                * that seems silly, no? 
  1953.                */
  1954.  
  1955.             case 0:
  1956.             case TOP:
  1957.             case BOTTOM:
  1958.             case TOP | BOTTOM:
  1959.             case LEFT:
  1960.             case RIGHT:
  1961.             case LEFT | RIGHT:
  1962.               if ((*fp) & LRREL)
  1963.             orng.lr += dn;
  1964.               if ((*fp) & HRREL)
  1965.             orng.hr += dn;
  1966.               if ((*fp) & LCREL)
  1967.             orng.lc += ov;
  1968.               if ((*fp) & HCREL)
  1969.             orng.hc += ov;
  1970.               break;
  1971.  
  1972.               /* If the referenced range contains rows or columns that
  1973.                * are entirely within the region being moved, then 
  1974.                * the region is moved, shrunk or stretched.
  1975.                */
  1976.             case LEFT | BOTTOM | TOP:
  1977.             case RIGHT | BOTTOM | TOP:
  1978.             case RIGHT | LEFT | TOP:
  1979.             case RIGHT | LEFT | BOTTOM:
  1980.             case RIGHT | LEFT | BOTTOM | TOP:
  1981.               if (fn != LEFT | BOTTOM | TOP)
  1982.             orng.hc += ov;
  1983.               if (fn != RIGHT | BOTTOM | TOP)
  1984.             orng.lc += ov;
  1985.               if (fn != RIGHT | LEFT | TOP)
  1986.             orng.hr += dn;
  1987.               if (fn != RIGHT | LEFT | BOTTOM)
  1988.             orng.lr += dn;
  1989.               break;
  1990.             }
  1991.           PUT_RNG (fp + 1, &orng); /* Patch the bytecode. */
  1992.  
  1993.           push_stack (moving, (VOIDSTAR) fp);
  1994.           push_stack (moving, (VOIDSTAR) TO_MAGIC (rr + dn, cc + ov));
  1995.           push_stack (moving, DEF_RNG);
  1996.           break;
  1997.  
  1998.         default:
  1999.           {
  2000.             struct function *fun;
  2001.  
  2002.             if (*fp < USR1)
  2003.               fun = &the_funs[*fp];
  2004.             else
  2005.               fun = &usr_funs[*fp - USR1][fp[1]];
  2006.  
  2007.             if (fun->fn_comptype & C_T)
  2008.               {
  2009.             flush_ref_fm (&timer_cells, rr, cc);
  2010.             add_ref_fm (&timer_cells, rr + dn, cc + ov);
  2011.               }
  2012.           }
  2013.           break;
  2014.         }
  2015.  
  2016.         }
  2017.     }
  2018.  
  2019.       /* Next, adjust references TO the region */
  2020.       for (n = 0; cp->cell_refs_from && n < cp->cell_refs_from->refs_used; n++)
  2021.     {
  2022.       /* The second enclosed loop over the bytecode will fix all of the
  2023.        * references to this cell.  This loop is here because a 
  2024.        * refs_fm structure may contain more than one occurence of the
  2025.        * referencing cell.  We don't want to adjust the same bytecode
  2026.        * twice.
  2027.        */
  2028.       while ((n < cp->cell_refs_from->refs_used - 1)
  2029.          && (cp->cell_refs_from->fm_refs[n].ref_row == 
  2030.              cp->cell_refs_from->fm_refs[n + 1].ref_row)
  2031.          && (cp->cell_refs_from->fm_refs[n].ref_col == 
  2032.              cp->cell_refs_from->fm_refs[n + 1].ref_col))
  2033.         ++n;
  2034.  
  2035.       /* For each cell that referenced this one, look
  2036.        * at the type of reference involved
  2037.        */
  2038.       frr = cp->cell_refs_from->fm_refs[n].ref_row;
  2039.       fcc = cp->cell_refs_from->fm_refs[n].ref_col;
  2040.  
  2041.       /* Unless the reference is from inside the region we're moving, in 
  2042.        * which case, it has already been adjusted.
  2043.        * 
  2044.        * (This test seems unnecessary but harmless. -tl)
  2045.        */
  2046.       if (BETWEEN (frr, fm->lr, fm->hr) && BETWEEN (fcc, fm->lc, fm->hc))
  2047.         continue;
  2048.  
  2049.       /* Find the cell that references cp. */
  2050.       fcp = find_cell (frr, fcc);
  2051.  
  2052.       /* Search the byte-code for the reference. */
  2053.       for (fn = 0; fcp->cell_refs_to && fn < fcp->cell_refs_to->refs_used; fn++)
  2054.         {
  2055.  
  2056.           ffp = &(fcp->cell_formula[fcp->cell_refs_to->to_refs[fn]]);
  2057.           switch (*ffp)
  2058.         {
  2059.         case R_CELL:
  2060.         case R_CELL | ROWREL:
  2061.         case R_CELL | COLREL:
  2062.         case R_CELL | ROWREL | COLREL:
  2063.  
  2064.           trr = GET_ROW (ffp + 1);
  2065.           tcc = GET_COL (ffp + 1);
  2066.  
  2067.           if (trr != rr || tcc != cc)
  2068.             continue;
  2069.  
  2070.           /* Found it!  Find the cell that fcp should be referencing now. */
  2071.           if (!((*ffp) & ROWREL))
  2072.             {
  2073.               trr += dn;
  2074.               PUT_ROW (ffp + 1, trr);
  2075.             }
  2076.           if (!((*ffp) & COLREL))
  2077.             {
  2078.               tcc += ov;
  2079.               PUT_COL (ffp + 1, tcc);
  2080.             }
  2081.           else
  2082.             /* If this is an absolute reference, it doesn't change. */
  2083.             continue;
  2084.  
  2085.           if (BETWEEN (trr, fm->lr, fm->hr) && BETWEEN (tcc, fm->lc, fm->hc))
  2086.             {
  2087.               push_stack (moving, (VOIDSTAR) TO_MAGIC (frr, fcc));
  2088.               push_stack (moving, (VOIDSTAR) TO_MAGIC (trr, tcc));
  2089.               push_stack (moving, DEF_REF);
  2090.             }
  2091.           else
  2092.             {
  2093.               cp = find_or_make_cell (trr, tcc);
  2094.               add_ref_fm (&(cp->cell_refs_from), frr, fcc);
  2095.             }
  2096.           goto flushref;
  2097.  
  2098.         case VAR:
  2099.           bcopy (&ffp[1], &v, sizeof (struct var *));
  2100.           switch (v->var_flags)
  2101.             {
  2102.             case VAR_UNDEF:
  2103.               break;
  2104.  
  2105.             case VAR_CELL:
  2106.               if (v->v_rng.lr == rr || v->v_rng.lc == cc)
  2107.             /* Right variable */
  2108.             continue;
  2109.               break;
  2110.  
  2111.             case VAR_RANGE:
  2112.               if (BETWEEN (rr, v->v_rng.lr, v->v_rng.hr) && BETWEEN (cc, v->v_rng.lc, v->v_rng.hc))
  2113.             continue;
  2114.               break;
  2115.             }
  2116.           break;
  2117.  
  2118.         case RANGE:
  2119.         case RANGE | LRREL:
  2120.         case RANGE | LRREL | LCREL:
  2121.         case RANGE | LRREL | LCREL | HCREL:
  2122.         case RANGE | LRREL | HCREL:
  2123.         case RANGE | LRREL | HRREL:
  2124.         case RANGE | LRREL | HRREL | LCREL:
  2125.         case RANGE | LRREL | HRREL | LCREL | HCREL:
  2126.         case RANGE | LRREL | HRREL | HCREL:
  2127.         case RANGE | HRREL:
  2128.         case RANGE | HRREL | LCREL:
  2129.         case RANGE | HRREL | LCREL | HCREL:
  2130.         case RANGE | HRREL | HCREL:
  2131.         case RANGE | LCREL:
  2132.         case RANGE | LCREL | HCREL:
  2133.         case RANGE | HCREL:
  2134.           GET_RNG (ffp + 1, &orng);
  2135.  
  2136.           if (!BETWEEN (rr, orng.lr, orng.hr) || !BETWEEN (cc, orng.lc, orng.hc))
  2137.             break;
  2138.  
  2139.           val = ((BETWEEN (orng.hc, fm->lc, fm->hc) << 3) /* right */
  2140.              + (BETWEEN (orng.lc, fm->lc, fm->hc) << 2) /* left */
  2141.              + (BETWEEN (orng.hr, fm->lr, fm->hr) << 1) /* bottom */
  2142.              + BETWEEN (orng.lr, fm->lr, fm->hr)); /* top */
  2143.  
  2144.           /* If the reference is absolute, or relative only in directions
  2145.            * that aren't changing, there's nothing to do. 
  2146.            */
  2147.           if (!(*ffp == RANGE
  2148.             || (!dn && ((*ffp) | LRREL | HRREL) == (RANGE | LRREL | HRREL))
  2149.             || (!ov && ((*ffp) | LCREL | HCREL) == (RANGE | LCREL | HCREL))))
  2150.             continue;
  2151.  
  2152.           /* If it's a case we don't know how to adjust, there's
  2153.            * nothing to do.  If there is no overlap, there's nothing to
  2154.            * do.
  2155.            */
  2156.           if ((val != (LEFT | BOTTOM | TOP))
  2157.               && (val != (RIGHT | BOTTOM | TOP))
  2158.               && (val != (RIGHT | LEFT | TOP))
  2159.               && (val != (RIGHT | LEFT | BOTTOM))
  2160.               && (val != (RIGHT | LEFT | BOTTOM | TOP)))
  2161.             continue;
  2162.           
  2163.           flush_range_ref (&orng, frr, fcc);
  2164.  
  2165.           if (val != RIGHT | LEFT | BOTTOM)
  2166.             orng.lr += dn;
  2167.           if (val != RIGHT | LEFT | TOP)
  2168.             orng.hr += dn;
  2169.           if (val != RIGHT | BOTTOM | TOP)
  2170.             orng.lc += ov;
  2171.           if (val != LEFT | BOTTOM  | TOP)
  2172.             orng.hc += ov;
  2173.           PUT_RNG (ffp + 1, &orng);
  2174.           push_stack (moving, (VOIDSTAR) ffp);
  2175.           push_stack (moving, (VOIDSTAR) TO_MAGIC (frr, fcc));
  2176.           push_stack (moving, DEF_RNG);
  2177.           continue;
  2178. #ifdef TEST
  2179.         default:
  2180.           { struct function *fun; if (*ffp < USR1) fun =
  2181.               &the_funs[*ffp]; else if (*ffp >= SKIP) fun = 0, panic
  2182.             ("SKIP? in shift_outside()"); else fun =
  2183.               &usr_funs[*ffp][ffp[1]];
  2184.             if ((fun->fn_comptype & C_T) == 0) io_error_msg
  2185.               ("Unknown byte (%d) for reference_to #%d %d",
  2186.                *ffp, fn, fcp->cell_refs_to->to_refs[fn]);
  2187.           }
  2188.           break; 
  2189. #endif
  2190.         }
  2191.           
  2192.         flushref:
  2193.           /* If we get here, a ref from frr,fcc should be deleted. */
  2194.           flush_ref_fm (&(cp->cell_refs_from), frr, fcc);
  2195.         }
  2196.     }
  2197.     }
  2198.  
  2199.   while (ptr = pop_stack (moving))
  2200.     {
  2201.       if (ptr == DEF_REF)
  2202.     {
  2203.       val = (unsigned long) pop_stack (moving);
  2204.       trr = MAGIC_ROW (val);
  2205.       tcc = MAGIC_COL (val);
  2206.       val = (unsigned long) pop_stack (moving);
  2207.       cp = find_or_make_cell (trr, tcc);
  2208.       add_ref_fm (&(cp->cell_refs_from), MAGIC_ROW (val), MAGIC_COL (val));
  2209.     }
  2210.       else if (ptr == DEF_RNG)
  2211.     {
  2212.       val = (unsigned long) pop_stack (moving);
  2213.       cur_row = MAGIC_ROW (val);
  2214.       cur_col = MAGIC_COL (val);
  2215.       ffp = (unsigned char *) pop_stack (moving);
  2216.  
  2217.       GET_RNG (ffp + 1, &orng);
  2218.       add_range_ref (&orng);
  2219.       if (my_cell)
  2220.         panic ("shift_outside: my_cell lost.");
  2221.       /* If this panic occurs, the caller should be recomputing
  2222.        * my_cell after shift_outside returns (and this useful panic
  2223.        * will have to be removed or my_cell set temporarily to 0).
  2224.        */
  2225.     }
  2226. #ifdef TEST
  2227.       else
  2228.     panic ("Now what (%p)?", ptr);
  2229. #endif
  2230.     }
  2231.   /* flush_stack(moving); */
  2232. }
  2233.  
  2234. /* The formula in cell my_cell has moved by DN down and OV over, adjust
  2235.    everything so it'll still work */
  2236. #ifdef __STDC__
  2237. void
  2238. shift_formula (int r, int c, int dn, int ov)
  2239. #else
  2240. void
  2241. shift_formula (r, c, dn, ov)
  2242.      int r;            /* Address of my_cell. */
  2243.      int c;
  2244.      int dn;
  2245.      int ov;
  2246. #endif
  2247. {
  2248.   int n;
  2249.   unsigned char *fp;
  2250.  
  2251.   for (n = 0; n < my_cell->cell_refs_to->refs_used; n++)
  2252.     {
  2253.       fp = &(my_cell->cell_formula[my_cell->cell_refs_to->to_refs[n]]);
  2254.       switch (*fp)
  2255.     {
  2256.     case F_ROW:
  2257.     case F_COL:
  2258.       push_cell (cur_row, cur_col);
  2259.       break;
  2260.  
  2261.     case R_CELL:
  2262.     case R_CELL | ROWREL:
  2263.     case R_CELL | COLREL:
  2264.     case R_CELL | ROWREL | COLREL:
  2265.       {
  2266.         CELLREF trr, tcc;
  2267.         CELL *tcp;
  2268.  
  2269.         /* These are more difficult */
  2270.         trr = GET_ROW (fp + 1);
  2271.         tcc = GET_COL (fp + 1);
  2272.         tcp = find_cell (trr, tcc);
  2273. #ifdef TEST
  2274.         if (!tcp)
  2275.           panic ("Can't find_cell(%s) in shift_formula", cell_name (trr, tcc));
  2276. #endif
  2277.         flush_ref_fm (&(tcp->cell_refs_from), cur_row - dn, cur_col - ov);
  2278.  
  2279.         if (((*fp) & ROWREL) && dn)
  2280.           {
  2281.         trr += dn;
  2282.         PUT_ROW (fp + 1, trr);
  2283.           }
  2284.         if (((*fp) & COLREL) && ov)
  2285.           {
  2286.         tcc += ov;
  2287.         PUT_COL (fp + 1, tcc);
  2288.           }
  2289.         tcp = find_or_make_cell (trr, tcc);
  2290.         add_ref_fm (&(tcp->cell_refs_from), cur_row, cur_col);
  2291.       }
  2292.       break;
  2293.  
  2294.     case RANGE:
  2295.     case RANGE | LRREL:
  2296.     case RANGE | LRREL | LCREL:
  2297.     case RANGE | LRREL | LCREL | HCREL:
  2298.     case RANGE | LRREL | HCREL:
  2299.     case RANGE | LRREL | HRREL:
  2300.     case RANGE | LRREL | HRREL | LCREL:
  2301.     case RANGE | LRREL | HRREL | LCREL | HCREL:
  2302.     case RANGE | LRREL | HRREL | HCREL:
  2303.     case RANGE | HRREL:
  2304.     case RANGE | HRREL | LCREL:
  2305.     case RANGE | HRREL | LCREL | HCREL:
  2306.     case RANGE | HRREL | HCREL:
  2307.     case RANGE | LCREL:
  2308.     case RANGE | LCREL | HCREL:
  2309.     case RANGE | HCREL:
  2310.       {
  2311.         struct rng orng;
  2312.         GET_RNG (fp + 1, &orng);
  2313.  
  2314.         flush_range_ref (&orng, cur_row - dn, cur_col - ov);
  2315.  
  2316.         if ((*fp) & LRREL)
  2317.           orng.lr += dn;
  2318.         if ((*fp) & HRREL)
  2319.           orng.hr += dn;
  2320.         if ((*fp) & LCREL)
  2321.           orng.lc += ov;
  2322.         if ((*fp) & HCREL)
  2323.           orng.hc += ov;
  2324.         PUT_RNG (fp + 1, &orng);
  2325.         add_range_ref (&orng);
  2326.         /* sparse array bug fixed here */
  2327.         my_cell = find_cell (r, c);
  2328.       }
  2329.       break;
  2330.  
  2331.     case VAR:
  2332.       {
  2333.         struct var *v;
  2334.         struct cell *tcp;
  2335.  
  2336.         bcopy (&fp[1], &v, sizeof (struct var *));
  2337.         flush_ref_fm (&(v->var_ref_fm), cur_row - dn, cur_col - ov);
  2338.         add_ref_fm (&(v->var_ref_fm), cur_row, cur_col);
  2339.         switch (v->var_flags)
  2340.           {
  2341.           case VAR_UNDEF:
  2342.         break;
  2343.  
  2344.           case VAR_CELL:
  2345.         tcp = find_cell (v->v_rng.lr, v->v_rng.lc);
  2346. #ifdef TEST
  2347.         if (!tcp)
  2348.           panic ("Can't find_cell(%s) in shift_formula", cell_name (v->v_rng.lr, v->v_rng.lc));
  2349. #endif
  2350.         flush_ref_fm (&(tcp->cell_refs_from), cur_row - dn, cur_col - ov);
  2351.         add_ref_fm (&(tcp->cell_refs_from), cur_row, cur_col);
  2352.         break;
  2353.  
  2354.           case VAR_RANGE:
  2355.         flush_range_ref (&(v->v_rng), cur_row - dn, cur_col - ov);
  2356.         add_range_ref (&(v->v_rng));
  2357.         /* sparse array bug fixed here */
  2358.         my_cell = find_cell (r, c);
  2359.         break;
  2360.  
  2361. #ifdef TEST
  2362.           default:
  2363.         panic ("Unknown var type %d", v->var_flags);
  2364. #endif
  2365.           }
  2366.       }
  2367.       break;
  2368.  
  2369.     default:
  2370.       {
  2371.         struct function *fun;
  2372.  
  2373.         if (*fp < USR1)
  2374.           fun = &the_funs[*fp];
  2375. #ifdef TEST
  2376.         else if (*fp >= SKIP)
  2377.           fun = 0, panic ("SKIP? in shift_formula?");
  2378. #endif
  2379.         else
  2380.           fun = &usr_funs[*fp][fp[1]];
  2381.         /* These are easy */
  2382.         if (fun->fn_comptype & C_T)
  2383.           {
  2384.         flush_ref_fm (&timer_cells, cur_row - dn, cur_col - ov);
  2385.         add_ref_fm (&timer_cells, cur_row, cur_col);
  2386.           }
  2387. #ifdef TEST
  2388.         else
  2389.           panic ("How do I deal with byte %d in shift_formula()?", *fp);
  2390. #endif
  2391.       }
  2392.       break;
  2393.     }
  2394.     }
  2395. }
  2396.  
  2397.  
  2398. /* ---------------- Routines for dealing with async functions -------------- */
  2399.  
  2400.  
  2401. /* This function is called when the alarm has gone off (but not from inside
  2402.  * the signal handler!). It schedules timer_cells->fm_refs for recalc. 
  2403.  */
  2404. #ifdef __STDC__
  2405. void
  2406. deal_alarm (void)
  2407. #else
  2408. void
  2409. deal_alarm ()
  2410. #endif
  2411. {
  2412.   int n;
  2413.   static time_t last_time = 0;
  2414.   if (alarm_active)
  2415.     {
  2416.       time_t this_time = time(0);
  2417.       if ((this_time - last_time) < alarm_seconds)
  2418.     return;
  2419.       last_time = this_time;
  2420.       current_cycle++;
  2421.       for (n = 0; n < timer_cells->refs_used; n++)
  2422.     push_cell (timer_cells->fm_refs[n].ref_row,
  2423.            timer_cells->fm_refs[n].ref_col);
  2424.     }
  2425. }
  2426.  
  2427. /* All the timer_cells are going away, 'cuz everything is going away. . . */
  2428. void
  2429. flush_all_timers ()
  2430. {
  2431.   if (timer_active)
  2432.     {
  2433. #ifdef SPLIT_REFS
  2434.       timer_cells->refs_used = 0;
  2435. #else
  2436.       flush_fm_ref (timer_cells);
  2437.       timer_cells = 0;
  2438. #endif
  2439.       timer_active = 0;
  2440.       alarm_active = 0;
  2441.     }
  2442. }
  2443.  
  2444. /* Add CUR_ROW, CUR_COL to the list of active timer-cells, turning on
  2445.    the timer_active, if it isn't already */
  2446. void
  2447. add_timer_ref (whereto)
  2448.      int whereto;
  2449. {
  2450.   add_ref_to (whereto);
  2451.   add_ref_fm (&timer_cells, cur_row, cur_col);
  2452.   if (!timer_active)
  2453.     {
  2454.       timer_active++;
  2455.       alarm_active = 1;
  2456.     }
  2457. }
  2458.  
  2459. /* ---------- Routines and vars for dealing with the eval FIFO ------------ */
  2460. static struct cell_buf cell_buffer;
  2461.  
  2462. /* Start up the FIFO of cells to update */
  2463. void
  2464. init_refs ()
  2465. {
  2466.   cell_buffer.size = FIFO_START;
  2467.   cell_buffer.buf = (struct pos *) ck_malloc (cell_buffer.size * sizeof (struct pos));
  2468.   bzero (cell_buffer.buf, cell_buffer.size * sizeof (struct pos));
  2469.   cell_buffer.push_to_here = cell_buffer.buf;
  2470.   cell_buffer.pop_frm_here = cell_buffer.buf;
  2471.   the_vars = hash_new ();
  2472. }
  2473.  
  2474. /* Push the cells in REF onto the FIFO.  This calls push_cell to do the
  2475.    actual work. . . */
  2476. void
  2477. push_refs (ref)
  2478.      struct ref_fm *ref;
  2479. {
  2480.   int n;
  2481.  
  2482.   if (!ref || !ref->refs_used)
  2483.     return;
  2484.   n = ref->refs_used;
  2485.   while (n--)
  2486.     {
  2487. #ifdef TEST
  2488.       CELL *cp;
  2489.  
  2490.       if (debug & 04)
  2491.     io_error_msg ("Push %s", cell_name (ref->fm_refs[n].ref_row, ref->fm_refs[n].ref_col));
  2492.       cp = find_cell (ref->fm_refs[n].ref_row, ref->fm_refs[n].ref_col);
  2493.       if (cp->cell_cycle == current_cycle)
  2494.     {
  2495.       if (debug & 01)
  2496.         io_error_msg ("Cycle detected from %s to %s",
  2497.               cell_name (cur_row, cur_col),
  2498.           cell_name (ref->fm_refs[n].ref_row, ref->fm_refs[n].ref_col));
  2499.       push_cell (ref->fm_refs[n].ref_row,
  2500.              ref->fm_refs[n].ref_col);
  2501.     }
  2502.       else
  2503. #endif
  2504.     push_cell (ref->fm_refs[n].ref_row, ref->fm_refs[n].ref_col);
  2505.     }
  2506. }
  2507.  
  2508. /* Push a cell onto the FIFO of cells to evaluate, checking for cells
  2509.    that are already on the FIFO, etc.
  2510.  
  2511.    This does not implement best-order recalculation, since there may be
  2512.    intersecting branches in the dependency tree, however, it's close enough
  2513.    for most people.
  2514.  */
  2515. #if __STDC__
  2516. void
  2517. push_cell (CELLREF row, CELLREF col)
  2518. #else
  2519. void
  2520. push_cell (row, col)
  2521.      CELLREF row;
  2522.      CELLREF col;
  2523. #endif
  2524. {
  2525.   struct pos *dup;
  2526.   CELL *cp;
  2527.   struct ref_fm *rf;
  2528.  
  2529.   if (cell_buffer.push_to_here + 1 == cell_buffer.pop_frm_here || (cell_buffer.pop_frm_here == cell_buffer.buf && cell_buffer.push_to_here == cell_buffer.buf + (cell_buffer.size - 1)))
  2530.     {
  2531.       int f, t, from_num;
  2532.  
  2533.       f = cell_buffer.pop_frm_here - cell_buffer.buf;
  2534.       t = cell_buffer.push_to_here - cell_buffer.buf;
  2535.       from_num = cell_buffer.size - f;
  2536.  
  2537.       cell_buffer.size FIFO_INC;
  2538.       cell_buffer.buf = (struct pos *) ck_realloc ((VOIDSTAR) cell_buffer.buf, cell_buffer.size * sizeof (struct pos));
  2539.       if (t == 0)
  2540.     {
  2541.       cell_buffer.push_to_here = cell_buffer.buf + f + from_num;
  2542.       cell_buffer.pop_frm_here = cell_buffer.buf + f;
  2543.     }
  2544.       else if (t > f)
  2545.     {
  2546.       cell_buffer.push_to_here = cell_buffer.buf + t;
  2547.       cell_buffer.pop_frm_here = cell_buffer.buf + f;
  2548.     }
  2549.       else
  2550.     {
  2551.       cell_buffer.push_to_here = cell_buffer.buf + t;
  2552.       cell_buffer.pop_frm_here = cell_buffer.buf + (cell_buffer.size - from_num);
  2553.       if (from_num)
  2554.         bcopy (cell_buffer.buf + f,
  2555.            cell_buffer.pop_frm_here,
  2556.            from_num * sizeof (struct pos));
  2557.     }
  2558.     }
  2559.  
  2560. #if 1
  2561.   if (cell_buffer.pop_frm_here != cell_buffer.push_to_here)
  2562.     {
  2563.       dup = cell_buffer.pop_frm_here;
  2564.  
  2565.       cp = find_cell (row, col);
  2566.       if (!cp)
  2567.     {
  2568.       return;
  2569.     }
  2570.       rf = cp->cell_refs_from;
  2571.       for (; dup != cell_buffer.push_to_here;)
  2572.     {
  2573.       if (dup->row == row && dup->col == col)
  2574.         {
  2575. #ifdef TEST
  2576.           if (debug & 010)
  2577.         io_error_msg ("Flushed dup ref to %s", cell_name (row, col));
  2578. #endif
  2579.           *dup = *(cell_buffer.pop_frm_here);
  2580.           cell_buffer.pop_frm_here++;
  2581.           if (cell_buffer.pop_frm_here == cell_buffer.buf + cell_buffer.size)
  2582.         cell_buffer.pop_frm_here = cell_buffer.buf;
  2583.           break;
  2584.         }
  2585. #if 0
  2586.       if (rf)
  2587.         {
  2588.           for (n = 0; n < rf->refs_used; n++)
  2589.         if (rf->fm_refs[n].ref_row == dup->row && rf->fm_refs[n].ref_col == dup->col)
  2590.           {
  2591. #ifdef TEST
  2592.             if (debug & 01)
  2593.               io_error_msg ("Swapped %s and %s", cell_name (row, col), cell_name (dup->row, dup->col));
  2594. #endif
  2595.             dup->row = row;
  2596.             dup->col = col;
  2597.             row = rf->fm_refs[n].ref_row;
  2598.             col - rf->fm_refs[n].ref_col;
  2599.             goto breakout;
  2600.           }
  2601.         }
  2602. #endif
  2603.  
  2604.       if (++dup == cell_buffer.buf + cell_buffer.size)
  2605.         dup = cell_buffer.buf;
  2606.     }
  2607.     }
  2608. #endif
  2609.  
  2610.   cell_buffer.push_to_here->row = row;
  2611.   cell_buffer.push_to_here->col = col;
  2612.   cell_buffer.push_to_here++;
  2613.   if (cell_buffer.push_to_here == cell_buffer.buf + cell_buffer.size)
  2614.     cell_buffer.push_to_here = cell_buffer.buf;
  2615. }
  2616.  
  2617. /* Pop a cell off CELL_BUFFER, and evaluate it, displaying the result. . .
  2618.    This returns 0 if there are no more cells to update, or if it gets
  2619.    an error. */
  2620.  
  2621. int
  2622. eval_next_cell ()
  2623. {
  2624.   CELL *cp;
  2625.   static loop_counter = 40;
  2626.  
  2627.   if (cell_buffer.pop_frm_here == cell_buffer.push_to_here)
  2628.     return 0;
  2629.  
  2630.   cur_row = cell_buffer.pop_frm_here->row;
  2631.   cur_col = cell_buffer.pop_frm_here->col;
  2632.   cell_buffer.pop_frm_here++;
  2633.   if (cell_buffer.pop_frm_here == cell_buffer.buf + cell_buffer.size)
  2634.     cell_buffer.pop_frm_here = cell_buffer.buf;
  2635.  
  2636.   cp = find_cell (cur_row, cur_col);
  2637.   if (cp)
  2638.     {
  2639.       if (cp->cell_cycle == current_cycle)
  2640.     --loop_counter;
  2641.       else
  2642.     loop_counter = 40;
  2643.       update_cell (cp);
  2644.       io_pr_cell (cur_row, cur_col, cp);
  2645.       return loop_counter;
  2646.     }
  2647.   else
  2648.     return 0;
  2649. }
  2650.  
  2651. #ifdef TEST
  2652. void
  2653. cell_buffer_contents ()
  2654. {
  2655.   struct pos *ptr;
  2656.  
  2657.   if (cell_buffer.pop_frm_here != cell_buffer.push_to_here)
  2658.     {
  2659.       ptr = cell_buffer.pop_frm_here;
  2660.       for (;;)
  2661.     {
  2662.       printf ("Ref to %s\r\n", cell_name (ptr->row, ptr->col));
  2663.       if (++ptr == cell_buffer.buf + cell_buffer.size)
  2664.         ptr = cell_buffer.buf;
  2665.       if (ptr == cell_buffer.push_to_here)
  2666.         break;
  2667.     }
  2668.     }
  2669.   printf ("End of buffer\r\n");
  2670. }
  2671.  
  2672. #endif
  2673.  
  2674. /* ----------------- Routines for dealing with variables ------------------ */
  2675.  
  2676. /* This sets the variable V_NAME to V_NEWVAL
  2677.    It returns error msg, or 0 on success.
  2678.    All the appropriate cells have their ref_fm arrays adjusted appropriatly
  2679.    This could be smarter; when changing a range var, only the cells that
  2680.    were in the old value but not in the new one need their references flushed,
  2681.    and only the cells that are new need references added.
  2682.    This might also be changed to use add_range_ref()?
  2683.  */
  2684. char *
  2685. new_var_value (v_name, v_namelen, v_newval)
  2686.      char *v_name;
  2687.      int v_namelen;
  2688.      char *v_newval;
  2689. {
  2690.   struct var *var;
  2691.   int n;
  2692.   int newflag;
  2693.   struct rng tmp_rng;
  2694.  
  2695.   cur_row = MIN_ROW;
  2696.   cur_col = MIN_COL;
  2697.   if (v_newval && *v_newval)
  2698.     {
  2699.       n = parse_cell_or_range (&v_newval, &tmp_rng);
  2700.       if (!n)
  2701.     return "Can't parse cell or range";
  2702.       if (*v_newval)
  2703.     return "Junk after cell or range";
  2704.       newflag = ((n | ROWREL | COLREL) == (R_CELL | ROWREL | COLREL)) ? VAR_CELL : VAR_RANGE;
  2705.     }
  2706.   else
  2707.     {
  2708.       tmp_rng.lr = tmp_rng.hr = NON_ROW;
  2709.       tmp_rng.lc = tmp_rng.hc = NON_COL;
  2710.       newflag = VAR_UNDEF;
  2711.     }
  2712.  
  2713.   var = find_or_make_var (v_name, v_namelen);
  2714.  
  2715.   if (var->var_ref_fm)
  2716.     {
  2717.       if (var->var_flags != VAR_UNDEF)
  2718.     {
  2719.       for (n = 0; n < var->var_ref_fm->refs_used; n++)
  2720.         {
  2721.           flush_range_ref (&(var->v_rng),
  2722.                    var->var_ref_fm->fm_refs[n].ref_row,
  2723.                    var->var_ref_fm->fm_refs[n].ref_col);
  2724.         }
  2725.     }
  2726.       var->v_rng = tmp_rng;
  2727.  
  2728.       if (var->v_rng.lr != NON_ROW)
  2729.     {
  2730.       for (n = 0; n < var->var_ref_fm->refs_used; n++)
  2731.         {
  2732.           cur_row = var->var_ref_fm->fm_refs[n].ref_row;
  2733.           cur_col = var->var_ref_fm->fm_refs[n].ref_col;
  2734.           add_range_ref (&(var->v_rng));
  2735.         }
  2736.     }
  2737.       for (n = 0; n < var->var_ref_fm->refs_used; n++)
  2738.     push_cell (var->var_ref_fm->fm_refs[n].ref_row,
  2739.            var->var_ref_fm->fm_refs[n].ref_col);
  2740.     }
  2741.   else
  2742.     var->v_rng = tmp_rng;
  2743.  
  2744.   var->var_flags = newflag;
  2745.  
  2746.   return 0;
  2747. }
  2748.  
  2749. void
  2750. #ifdef __STDC__
  2751. for_all_vars (void (*func) (char *, struct var *))
  2752. #else
  2753. for_all_vars (func)
  2754.      void (*func) ();
  2755. #endif
  2756. {
  2757.   hash_apply (the_vars, func);
  2758. }
  2759.  
  2760. /* Find a variable in the list of variables, or create it if it doesn't
  2761.    exist.  Takes a name and a length so the name doesn't have to be
  2762.    null-terminated
  2763.  */
  2764. struct var *
  2765. find_or_make_var (string, len)
  2766.      char *string;
  2767.      int len;
  2768. {
  2769.   struct var *ret;
  2770.   int ch;
  2771.  
  2772.   ch = string[len];
  2773.   string[len] = '\0';
  2774.  
  2775.   ret = (struct var *) hash_find (the_vars, string);
  2776.   if (ret)
  2777.     {
  2778.       string[len] = ch;
  2779.       return ret;
  2780.     }
  2781.  
  2782.   ret = (struct var *) ck_malloc (sizeof (struct var) + len);
  2783.   bcopy (string, ret->var_name, len + 1);
  2784.   ret->var_flags = VAR_UNDEF;
  2785.   ret->v_rng.lr = 0;
  2786.   ret->v_rng.lc = 0;
  2787.   ret->v_rng.hr = 0;
  2788.   ret->v_rng.hc = 0;
  2789.   ret->var_ref_fm = 0;
  2790.   hash_insert (the_vars, ret->var_name, ret);
  2791.   string[len] = ch;
  2792.   return ret;
  2793. }
  2794.  
  2795. /* Like find-or-make-var except returns 0 if it doesn't exist */
  2796. struct var *
  2797. find_var (string, len)
  2798.      char *string;
  2799.      int len;
  2800. {
  2801.   int ch;
  2802.   struct var *ret;
  2803.  
  2804.   ch = string[len];
  2805.   string[len] = '\0';
  2806.   ret = (struct var *) hash_find (the_vars, string);
  2807.   string[len] = ch;
  2808.   return ret;
  2809. }
  2810.  
  2811. /* This adds a reference from CUR_ROW,CUR_COL to the variable VAR
  2812.    It calls add_ref or add_range_ref to have the cell(s) in VAR be
  2813.    referenced by CUR_ROW,CUR_COL
  2814.  */
  2815. void
  2816. add_var_ref (vvar)
  2817.      void * vvar;
  2818. {
  2819.   struct var *var = (struct var *)vvar;
  2820.   add_ref_fm (&(var->var_ref_fm), cur_row, cur_col);
  2821.   switch (var->var_flags)
  2822.     {
  2823.     case VAR_UNDEF:
  2824.       break;
  2825.     case VAR_CELL:
  2826.       add_ref (var->v_rng.lr, var->v_rng.lc);
  2827.       break;
  2828.     case VAR_RANGE:
  2829.       add_range_ref (&(var->v_rng));
  2830.       break;
  2831. #ifdef TEST
  2832.     default:
  2833.       panic ("Unknown var type %d in add_var_ref", var->var_flags);
  2834. #endif
  2835.     }
  2836. }
  2837.  
  2838. static void
  2839. flush_var (name, var)
  2840.      char *name;
  2841.      struct var *var;
  2842. {
  2843. #ifdef SPLIT_REFS
  2844.   if (var->var_ref_fm)
  2845.     free (var->var_ref_fm);
  2846. #endif
  2847.   free (var);
  2848. }
  2849.  
  2850.  
  2851. /* Free up all the variables, and (if SPLIT_REFS) the ref_fm structure
  2852.    associated with each variable.  Note that this does not get rid of
  2853.    the struct var *s in cell expressions, so it can only be used when all
  2854.    the cells are being freed also
  2855.  */
  2856. #ifdef __STDC__
  2857. void
  2858. flush_variables (void)
  2859. #else
  2860. void
  2861. flush_variables ()
  2862. #endif
  2863. {
  2864.   for_all_vars (flush_var);
  2865.   hash_die (the_vars);
  2866.   the_vars = hash_new ();
  2867. }
  2868.